Index: /branches/rel_apv_10_7/GNUmakefile
===================================================================
--- /branches/rel_apv_10_7/GNUmakefile	(revision 39181)
+++ /branches/rel_apv_10_7/GNUmakefile	(working copy)
@@ -9,7 +9,7 @@
 UINET_SDK=${CLICK_LIB}/libuinet-atcp
 MAKESYSPATH=${CURDIR}/usr/src/share/mk
 RTE_SDK=${CURDIR}/usr/click/lib/libintel_dpdk
-RTE_KERNELDIR=/lib/modules/3.10.0-327.28.2.21.el7.x86_64/build
+RTE_KERNELDIR=/lib/modules/3.10.0-327.28.2.22.el7.x86_64/build
 LIBPCAP_DIR=${CLICK_LIB}/libpcap
 RTE_TARGET=x86_64-default-linuxapp-gcc
 REL=$(shell /usr/bin/awk '{print $$1}' usr/click/lib/libversion/tag)
Index: /branches/rel_apv_10_7/tools/image_creator.sh
===================================================================
--- /branches/rel_apv_10_7/tools/image_creator.sh	(revision 39181)
+++ /branches/rel_apv_10_7/tools/image_creator.sh	(working copy)
@@ -27,7 +27,7 @@
 MACHINE_ARCH=`uname -m`
 
 if [ "x$IMAGE_TARGET" = "xaws" ]; then
-KERNEL_VERSION=3.10.0-327.28.2.21.el7.x86_64
+KERNEL_VERSION=3.10.0-327.28.2.22.el7.x86_64
 fi
 
 # create base image
Index: /branches/rel_apv_10_7/tools/update/ustacksystem.ks
===================================================================
--- /branches/rel_apv_10_7/tools/update/ustacksystem.ks	(revision 39181)
+++ /branches/rel_apv_10_7/tools/update/ustacksystem.ks	(working copy)
@@ -30,12 +30,12 @@
 gcc-4.8.5-4.el7.x86_64
 rpm-build-4.11.3-17.el7.x86_64
 redhat-rpm-config-9.1.0-68.el7.centos.noarch
-kernel-devel-3.10.0-327.28.2.21.el7.x86_64
+kernel-devel-3.10.0-327.28.2.22.el7.x86_64
 lldpd-1.0.4-1.1.x86_64
 cloud-init-18.2-1.el7.x86_64
 open-vm-tools-9.10.2-4.el7.x86_64
 bash-4.2.46-19.el7.x86_64
-kernel-3.10.0-327.28.2.21.el7.x86_64
+kernel-3.10.0-327.28.2.22.el7.x86_64
 passwd-0.79-4.el7.x86_64
 policycoreutils-2.2.5-20.el7.x86_64
 chkconfig-1.3.61-5.el7.x86_64
@@ -332,7 +332,7 @@
 snappy-1.1.0-3.el7.x86_64
 sysvinit-tools-2.88-14.dsf.el7.x86_64
 libnetfilter_conntrack-1.0.4-2.el7.x86_64
-iproute-3.10.0-54.el7.x86_64
+iproute-4.11.0-30.el7.x86_64
 libXau-1.0.8-2.1.el7.x86_64
 libthai-0.1.14-9.el7.x86_64
 harfbuzz-0.9.36-1.el7.x86_64
Index: /branches/rel_apv_10_7/tools/update_for_vendor.sh
===================================================================
--- /branches/rel_apv_10_7/tools/update_for_vendor.sh	(revision 39181)
+++ /branches/rel_apv_10_7/tools/update_for_vendor.sh	(working copy)
@@ -15,6 +15,6 @@
 	echo "intel"
 	pushd  usr/click/lib/mlnx/ > /dev/null
 	tar zxf MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext.tgz 
-	./MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext/mlnxofedinstall --kernel 3.10.0-327.28.2.21.el7.x86_64 --kernel-sources /lib/modules/3.10.0-327.28.2.21.el7.x86_64/build --skip-kmp-verify --force
+	./MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext/mlnxofedinstall --kernel 3.10.0-327.28.2.22.el7.x86_64 --kernel-sources /lib/modules/3.10.0-327.28.2.22.el7.x86_64/build --skip-kmp-verify --force
 	popd > /dev/null
 fi
Index: /branches/rel_apv_10_7/tools/ustackbuildenv.ks
===================================================================
--- /branches/rel_apv_10_7/tools/ustackbuildenv.ks	(revision 39181)
+++ /branches/rel_apv_10_7/tools/ustackbuildenv.ks	(working copy)
@@ -26,8 +26,8 @@
 
 bash-4.2.46-19.el7.x86_64
 sparsehash-devel-2.0.2-4.el7.x86_64
-kernel-3.10.0-327.28.2.21.el7.x86_64
-kernel-devel-3.10.0-327.28.2.21.el7.x86_64
+kernel-3.10.0-327.28.2.22.el7.x86_64
+kernel-devel-3.10.0-327.28.2.22.el7.x86_64
 syslinux-4.05-12.el7.x86_64
 passwd-0.79-4.el7.x86_64
 policycoreutils-2.2.5-20.el7.x86_64
@@ -249,7 +249,7 @@
 grep-2.20-2.el7.x86_64
 libnetfilter_conntrack-1.0.4-2.el7.x86_64
 libffi-3.0.13-16.el7.x86_64
-iproute-3.10.0-54.el7.x86_64
+iproute-4.11.0-30.el7.x86_64
 glib2-2.42.2-5.el7.x86_64
 kpartx-0.4.9-85.el7.x86_64
 libgpg-error-1.12-3.el7.x86_64
@@ -381,7 +381,7 @@
 python-pycurl-7.19.0-17.el7.x86_64
 fipscheck-lib-1.4.1-5.el7.x86_64
 krb5-devel-1.13.2-10.el7.x86_64
-kernel-headers-3.10.0-327.28.2.21.el7.x86_64
+kernel-headers-3.10.0-327.28.2.22.el7.x86_64
 libicu-50.1.2-15.el7.x86_64
 fontpackages-filesystem-1.44-8.el7.noarch
 msgpack-0.5.8-1.el7.x86_64
Index: /branches/rel_apv_10_7/tools/ustackbuildutils.py
===================================================================
--- /branches/rel_apv_10_7/tools/ustackbuildutils.py	(revision 39181)
+++ /branches/rel_apv_10_7/tools/ustackbuildutils.py	(working copy)
@@ -352,7 +352,7 @@
         if self.sys_os != 'uos' and self.arch != 'aarch64' and self.platform == FLATFORM_INTEL:
             mlnx_cmd = ['tar', 'xzf', './usr/click/lib/mlnx/MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext.tgz', '-C' './pack/install_root/tmp']
             log_exec(mlnx_cmd)
-            mlnx_cmd = ['chroot', 'pack/install_root', 'su', '-', 'root', '-c', 'cd /tmp/MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext && ./mlnxofedinstall --kernel 3.10.0-327.28.2.21.el7.x86_64 --kernel-sources /lib/modules/3.10.0-327.28.2.21.el7.x86_64/build --force']
+            mlnx_cmd = ['chroot', 'pack/install_root', 'su', '-', 'root', '-c', 'cd /tmp/MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext && ./mlnxofedinstall --kernel 3.10.0-327.28.2.22.el7.x86_64 --kernel-sources /lib/modules/3.10.0-327.28.2.22.el7.x86_64/build --force']
             log_exec(mlnx_cmd)
             mlnx_cmd = ['rm', '-rf', './pack/install_root/tmp/MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext']
             log_exec(mlnx_cmd)
Index: /branches/rel_apv_10_7/tools/ustackbuildutils.py3
===================================================================
--- /branches/rel_apv_10_7/tools/ustackbuildutils.py3	(revision 39181)
+++ /branches/rel_apv_10_7/tools/ustackbuildutils.py3	(working copy)
@@ -341,7 +341,7 @@
         if self.sys_os != 'uos' and self.arch != 'aarch64':
             mlnx_cmd = ['tar', 'xzf', './usr/click/lib/mlnx/MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext.tgz', '-C' './pack/install_root/tmp']
             log_exec(mlnx_cmd)
-            mlnx_cmd = ['chroot', 'pack/install_root', 'su', '-', 'root', '-c', 'cd /tmp/MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext && ./mlnxofedinstall --kernel 3.10.0-327.28.2.21.el7.x86_64 --kernel-sources /lib/modules/3.10.0-327.28.2.21.el7.x86_64/build --force']
+            mlnx_cmd = ['chroot', 'pack/install_root', 'su', '-', 'root', '-c', 'cd /tmp/MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext && ./mlnxofedinstall --kernel 3.10.0-327.28.2.22.el7.x86_64 --kernel-sources /lib/modules/3.10.0-327.28.2.22.el7.x86_64/build --force']
             log_exec(mlnx_cmd)
             mlnx_cmd = ['rm', '-rf', './pack/install_root/tmp/MLNX_OFED_LINUX-4.0-1.0.1.0-rhel7.2-ext']
             log_exec(mlnx_cmd)
Index: /branches/rel_apv_10_7/tools/vmlinuz/centos-kernel/SOURCES/kernel-3.10.0-x86_64-debug.config
===================================================================
--- /branches/rel_apv_10_7/tools/vmlinuz/centos-kernel/SOURCES/kernel-3.10.0-x86_64-debug.config	(revision 39181)
+++ /branches/rel_apv_10_7/tools/vmlinuz/centos-kernel/SOURCES/kernel-3.10.0-x86_64-debug.config	(working copy)
@@ -755,6 +755,7 @@
 # CONFIG_NET_FOU is not set
 # CONFIG_NET_FOU_IP_TUNNELS is not set
 CONFIG_GENEVE=m
+CONFIG_GENEVE_CORE=m
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
Index: /branches/rel_apv_10_7/tools/vmlinuz/centos-kernel/SOURCES/kernel-3.10.0-x86_64.config
===================================================================
--- /branches/rel_apv_10_7/tools/vmlinuz/centos-kernel/SOURCES/kernel-3.10.0-x86_64.config	(revision 39181)
+++ /branches/rel_apv_10_7/tools/vmlinuz/centos-kernel/SOURCES/kernel-3.10.0-x86_64.config	(working copy)
@@ -749,7 +749,8 @@
 CONFIG_NET_UDP_TUNNEL=m
 # CONFIG_NET_FOU is not set
 # CONFIG_NET_FOU_IP_TUNNELS is not set
-# CONFIG_GENEVE is not set
+CONFIG_GENEVE=m
+CONFIG_GENEVE_CORE=m
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
@@ -1245,6 +1246,7 @@
 CONFIG_OPENVSWITCH=m
 CONFIG_OPENVSWITCH_GRE=m
 CONFIG_OPENVSWITCH_VXLAN=m
+CONFIG_OPENVSWITCH_GENEVE=m
 CONFIG_VSOCKETS=m
 CONFIG_VMWARE_VMCI_VSOCKETS=m
 CONFIG_NETLINK_MMAP=y
Index: /branches/rel_apv_10_7/tools/vmlinuz/centos-kernel/SPECS/kernel.spec
===================================================================
--- /branches/rel_apv_10_7/tools/vmlinuz/centos-kernel/SPECS/kernel.spec	(revision 39181)
+++ /branches/rel_apv_10_7/tools/vmlinuz/centos-kernel/SPECS/kernel.spec	(working copy)
@@ -13,7 +13,7 @@
 
 %define rpmversion 3.10.0
 %define pkgrelease 327.28.2.el7
-%define ctpkgrelease 327.28.2.21.el7
+%define ctpkgrelease 327.28.2.22.el7
 
 %define pkg_release %{ctpkgrelease}%{?buildid}
 
@@ -395,6 +395,7 @@
 Patch1069701: perf-build-fix-linux-4.4.X-branch-and-RHEL7.4.patch
 Patch106970: array_serial_core.c.patch
 Patch999010: array_support_icelake_sp_cpu.patch
+Patch999011: array_add_geneve_kernel_support.patch
 
 BuildRoot: %{_tmppath}/kernel-%{KVRA}-root
 
@@ -720,6 +721,7 @@
 ApplyOptionalPatch perf-build-fix-linux-4.4.X-branch-and-RHEL7.4.patch
 ApplyOptionalPatch array_serial_core.c.patch
 ApplyOptionalPatch array_support_icelake_sp_cpu.patch
+ApplyOptionalPatch array_add_geneve_kernel_support.patch
 
 # Any further pre-build tree manipulations happen here.
 
Index: /branches/rel_apv_10_7/usr/click/bin/backend/Makefile
===================================================================
--- /branches/rel_apv_10_7/usr/click/bin/backend/Makefile	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/bin/backend/Makefile	(working copy)
@@ -1,7 +1,7 @@
 # ArrayOS
 NO_MAN=
 PROG=	backend
-SRCS=	sys_cmd.c backend.c segment_nat_auto.c ntp.c geneve.c sys_tool.c users.c engineering.c \
+SRCS=	sys_cmd.c backend.c segment_nat_auto.c ntp.c sys_tool.c users.c engineering.c \
 	engineering_commands.c sys_time.c sync_ui.c role.c \
 	utils.c sys_dump.c
 
Index: /branches/rel_apv_10_7/usr/click/bin/backend/geneve.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/bin/backend/geneve.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/bin/backend/geneve.c	(working copy)
@@ -1,143 +0,0 @@
-
-/*-----------------------------------------------------------------------
-*
-* Copyright (C) 2024
-* ArrayNetworks Inc. All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification is not permitted unless authorized in writing by a duly 
-* appointed officer of ClickArray Inc. or its derivatives
-*
-* UI Geneve
-*
-* $ArrayOS$
-*
-*-----------------------------------------------------------------------
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <netdb.h>
-
-#if __BSD_VISIBLE
-typedef	unsigned char	u_char;
-typedef	unsigned short	u_short;
-typedef	unsigned int	u_int;
-typedef	unsigned long	u_long;
-#ifndef _KERNEL
-typedef	unsigned short	ushort;		/* Sys V compatibility */
-typedef	unsigned int	uint;		/* Sys V compatibility */
-#endif
-#endif
-
-// set
-int set_geneve(char* geneve_name, u_int vni) {
-    printf("Set GENEVE: %s, VI number: %d\n", geneve_name, vni);
-    return 0;
-}
-
-int geneve_tunnel(char* tun_name, char* localip, char* dstip) {
-    printf("GENEVE tunnel: %s, localip: %s, dstip: %s\n", tun_name, localip, dstip);
-    return 0;
-}
-
-int geneve_bind(char* geneve_name, char* tun_name) {
-    printf("GENEVE : %s, tunnel name: %s\n", geneve_name, tun_name);
-    return 0;
-}
-
-int geneve_associate(char* geneve_name, char* port_name) {
-    printf("GENEVE : %s, port name: %s\n", geneve_name, port_name);
-    return 0;
-}
-
-// no
-int no_geneve(char* geneve_name) {
-	printf("no GENEVE : %s\n", geneve_name);
-    return 0;
-}
-
-int no_geneve_tunnel(char* tun_name) {
-    printf("no GENEVE tunnel : %s\n", tun_name);
-    return 0;
-}
-
-int no_geneve_bind(char* geneve_name, char* tun_name) {
-    printf("GENEVE : %s, tunnel name: %s\n", geneve_name, tun_name);
-    return 0;
-}
-
-int no_geneve_associate(char* geneve_name, char* port_name) {
-    printf("GENEVE : %s, port name: %s\n", geneve_name, port_name);
-    return 0;
-}
-
-// show
-int show_geneve_interface(void) {
-    printf("Show GENEVE interface\n");
-    return 0;
-}
-
-int show_geneve_port(void) {
-    printf("Show GENEVE port\n");
-    return 0;
-}
-
-int show_geneve_learn(void) {
-    printf("Show GENEVE learn\n");
-    return 0;
-}
-
-int show_geneve_bind(char* geneve_name) {
-    printf("Show GENEVE bind\n");
-    return 0;
-}
-
-int show_geneve_associate(char* geneve_name) {
-    printf("Show GENEVE associate\n");
-    return 0;
-}
-
-int show_geneve_tunnel(char *tun_name) {
-    printf("Show GENEVE tunnel\n");
-    return 0;
-}
-
-int show_geneve_forwarding(uint32_t vni, char* mac) {
-    printf("Show GENEVE forward vni: %d, mac: %s\n", vni, mac);
-    return 0;
-}
-
-int show_geneve_all(void) {
-    printf("Show GENEVE all\n");
-    return 0;
-}
-
-// // clear
-int clear_geneve_bind(char * geneve_name) {
-    printf("Clear GENEVE bind %s\n", geneve_name);
-    return 0;
-}
-
-int clear_geneve_associate(void) {
-    printf("Clear GENEVE associate\n");
-    return 0;
-}
-
-int clear_geneve_tunnel(void) {
-    printf("Clear GENEVE tunnel\n");
-    return 0;
-}
-
-int clear_geneve_interface(void) {
-    printf("Clear GENEVE interface\n");
-    return 0;
-}
-
-int clear_geneve_all(void) {
-    printf("Clear GENEVE all\n");
-    return 0;
-}
\ No newline at end of file
Index: /branches/rel_apv_10_7/usr/click/bin/backend/sys_tool.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/bin/backend/sys_tool.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/bin/backend/sys_tool.c	(working copy)
@@ -204,7 +204,7 @@
 static char *write_segment(char *segment);
 /*vxlan_support*/
 static char *write_vxlan_forwarding(void);
-
+static char *write_geneve_forwarding(void);
 static int port_link_clear(void);
 static int clear_aaa_session(void);
 static int llb_dns_clear(void);
@@ -569,26 +569,38 @@
     },
     {
     write_mnet,
-    CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL, 
+    CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL,
     "#mnet configuration" 
     },
     
     {
 	write_vxlan,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL, 
-	"#vxlan basic configuration" 
+	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL,
+	"#vxlan basic configuration"
     },
 
     {
 	write_vxlan_forwarding,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL, 
-	"#vxlan forwarding configuration" 
+	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL,
+	"#vxlan forwarding configuration"
     },
-    
+
+    {
+        write_geneve,
+        CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL,
+        "#geneve basic configuration"
+    },
+
+	{
+		write_geneve_forwarding,
+		CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL,
+		"#geneve forwarding configuration"
+	},
+
     {
 	write_overlap_if,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL, 
-	"#overlap interface configuration" 
+	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL,
+	"#overlap interface configuration"
     },
     {
 	write_bond_hc,
@@ -1881,39 +1893,43 @@
         CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL|CMD_PRIMARY
     },
     {
-	clear_ip_dhcp,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_PRIMARY 
+		clear_ip_dhcp,
+		CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_PRIMARY
     },
     {
-	ipv6_clear_ndp,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_PRIMARY|CMD_GLOBAL 
+		ipv6_clear_ndp,
+		CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_PRIMARY|CMD_GLOBAL
 	},
     {
-	clear_vxlan_all,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL|CMD_PRIMARY 
+		clear_vxlan_all,
+		CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL|CMD_PRIMARY
     },
     {
-	clear_ip_address,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_PRIMARY 
+        clear_geneve_all,
+        CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL|CMD_PRIMARY
     },
     {
-	clear_node_name_all,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL|CMD_PRIMARY 
+		clear_ip_address,
+		CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_PRIMARY
+    },
+    {
+		clear_node_name_all,
+		CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL|CMD_PRIMARY
     },
 
     {
-	clear_mnet,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL|CMD_PRIMARY 
+		clear_mnet,
+		CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL|CMD_PRIMARY
     },
 	
     {
-	clear_filter,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL
+		clear_filter,
+		CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL
     },
 
     {
-	clear_route,
-	CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL|CMD_PRIMARY 
+		clear_route,
+		CMD_NORMAL|CMD_ARRAYOS|CMD_SPROXY|CMD_GLOBAL|CMD_PRIMARY 
     },
    #if 0
     {
@@ -8184,10 +8200,6 @@
 	show_statistics_slb_all_kern();
 	segment_all_show_slb();
 
-	/* TCP */
-	printf("\n<<<< TCP Statistics >>>>\n\n");
-	tcp_statistic("");
-
 	printf("\n<<<< Health Check Status>>>>\n\n");
 	show_health_server("");
 
@@ -10284,7 +10296,20 @@
 	return buf;
 }
 
-static char *write_eroute(char *segment) 
+static char *write_geneve_forwarding(void)
+{
+
+	char *buf = NULL;
+	int  len;
+
+	if (write_geneve_forwarding_kern((void **) &buf, &len) < 0) {
+		return NULL;
+	}
+
+	return buf;
+}
+
+static char *write_eroute(char *segment)
 {
 	char *buf = NULL;
 	int  len;
Index: /branches/rel_apv_10_7/usr/click/bin/wwlogd/cafw_logd.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/bin/wwlogd/cafw_logd.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/bin/wwlogd/cafw_logd.c	(working copy)
@@ -306,7 +306,7 @@
 	 * nic should be started from 0
 	 * for (nic = 1; nic < MAX_NIC + MAX_VLAN; nic++)
 	 */
-	for (nic = 0; nic < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + MAX_VXLAN_TEST; nic++) {
+	for (nic = 0; nic < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + MAX_VXLAN_TEST + MAX_GENEVE; nic++) {
 	/*end of 10532*/
 		if (ca_ptr->ifnodes[nic] && ca_ptr->ifnodes[nic]->if_on) {
 			return 1;
Index: /branches/rel_apv_10_7/usr/click/lib/libcafw_cli/cafw.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libcafw_cli/cafw.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libcafw_cli/cafw.c	(working copy)
@@ -1764,6 +1764,7 @@
 {
 	vlan_ip_t	vlan;
 	vxlan_ip_t vxlan;
+	geneve_ip_t geneve;
 	int i;
 
 	if (nic_init() != IP_SUCCESS) {
@@ -1788,6 +1789,11 @@
 		return CAFW_VXLAN_OFFSET+ vxlan.num;
 	}
 
+	/* geneve support */
+	if (getgeneveif(name, &geneve) == 0) {
+		return CAFW_GENEVE_OFFSET+ geneve.num;
+	}
+
 	for (i = 0; i < *total_nic; i++) {
 		if (!strcmp(name, nic_ca[i].ca_id)) {
 			return i;
@@ -1805,6 +1811,7 @@
 {
 	static vlan_ip_t	vlan;
 	static vxlan_ip_t vxlan;
+	static geneve_ip_t geneve;
 	static char bond_name[BOND_ADAPTER_CA_NAME_LEN];
 
 	if (nic_init() != IP_SUCCESS) {
@@ -1827,10 +1834,15 @@
 	/* Link Aggregation, end */
 
 	/*add vxlan support*/
-	if (nic >= CAFW_VXLAN_OFFSET && getvxlanif_num(nic-CAFW_VXLAN_OFFSET, &vxlan) == 0) {
+	if (nic >= CAFW_VXLAN_OFFSET && nic < CAFW_GENEVE_OFFSET && getvxlanif_num(nic-CAFW_VXLAN_OFFSET, &vxlan) == 0) {
 		return vxlan.ifname;
 	}
 
+	/* geneve support */
+	if (nic >= CAFW_GENEVE_OFFSET && getgeneveif_num(nic - CAFW_GENEVE_OFFSET, &geneve) == 0) {
+		return geneve.ifname;
+	}
+
 	return NULL;
 }
 
Index: /branches/rel_apv_10_7/usr/click/lib/libip/ip.h
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libip/ip.h	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libip/ip.h	(working copy)
@@ -37,19 +37,35 @@
 	VXLAN_UNBOUND,
 	VXLAN_MCAST_TUN_BOUND,
 	VXLAN_P2P_TUN_BOUND
-	
 };
 
+enum {
+	GENEVE_MCAST_TUN_BOUND = 1,
+	GENEVE_P2P_TUN_BOUND
+};
+
+/* geneve support */
+#define MAX_GENEVE            (2048)
+#define MIN_GENEVE_VNI        1
+#define MAX_GENEVE_VNI        ((1 << 24) - 1)
+#define MAX_GENEVE_TUNNEL     64
+#define GENEVE_VNI_MAX_TUNNEL 12  /* Max tunnels a vni can reside on */
+
+enum {
+	GENEVE_UNBOUND,
+	GENEVE_BOUND,
+};
 
 #define SYSSIZE        (sizeof(sys_ip_t) * MAX_NIC)
 #define VLANSIZE       (sizeof(vlan_ip_t) * MAX_VLAN)
 #define MNETSIZE       (sizeof(mnet_ip_t) * MAX_MNET)
 #define VXLANSIZE       (sizeof(vxlan_ip_t) * MAX_VXLAN)
+#define GENEVESIZE      (sizeof(geneve_ip_t) * MAX_GENEVE)
 
 #define MNET_MAX_PARENT_INTERFACE	(MAX_NIC+MAX_VLAN+BOND_MAX_PSEUDO_CARDS)
 #define MNET_STATE_SIZE	(sizeof(mnet_state_t))
 
-#define MAX_NUM_IFNET  (MAX_VLAN+MAX_VXLAN+MAX_MNET+MAX_NIC)
+#define MAX_NUM_IFNET  (MAX_VLAN+MAX_VXLAN+MAX_MNET+MAX_NIC+MAX_GENEVE)
 
 #ifndef FALSE
 #define FALSE   0
@@ -64,7 +80,8 @@
 #define SHOW_INTF_VLAN    3
 #define SHOW_INTF_ALL     4
 #define SHOW_INTF_UNKONW  5
-#define SHOW_INTF_VXLAN    6
+#define SHOW_INTF_VXLAN   6
+#define SHOW_INTF_GENEVE  7
 
 #define SHOW_INTF_MAGICNO -1
 
@@ -117,6 +134,7 @@
     u_short vtag;
 	u_short is_segment;
 	int is_vxlan_associated;
+	int is_geneve_associated;
 	char vlan_info[CA_INFO];
 } vlan_ip_t;
 
@@ -141,6 +159,11 @@
 	VXLAN_TUN_MCAST
 };
 
+enum{
+	GENEVE_TUN_P2P,
+	GENEVE_TUN_MCAST
+};
+
 typedef struct _vxlan_tun_t {
     uint32_t local_ip32;
     uint32_t remote_ip32;
@@ -153,6 +176,34 @@
     int tun_mode;
 } vxlan_tun_t;
 
+typedef struct _geneve_ip_t {
+    uint32_t ip32;
+    uint32_t mask32;
+    char	 v6[INET6_ADDRSTRLEN];
+    int      prefixlen;
+    char     ifname[CA_NLEN];
+    char     real_ifname[CA_NLEN];
+	char     kni_ifname[CA_NLEN];
+    int      num;
+    int      vni;
+    int      bound_type;
+    char     geneve_tun[GENEVE_VNI_MAX_TUNNEL];
+    char     geneve_gw_if[CA_NLEN];
+    char     geneve_info[CA_INFO];
+} geneve_ip_t;
+
+typedef struct _geneve_tun_t {
+    uint32_t local_ip32;
+    uint32_t remote_ip32;
+    char	 local_v6[INET6_ADDRSTRLEN];
+    char	 remote_v6[INET6_ADDRSTRLEN];
+    char     tun_name[CA_NLEN];
+    int      num;
+    int      valid;
+    int      isipv6;
+	int      tun_mode;
+} geneve_tun_t;
+
 typedef struct _nic_rec_t {
     char hw_id[CA_HWLEN];
 #if defined(__linux__)
@@ -534,6 +585,8 @@
 int is_physical_if(char *nic_name);
 char* write_vxlan(void);
 int clear_vxlan_all(void);
+char *write_geneve(void);
+int clear_geneve_all(void);
 
 int get_ipv6_default_route(struct in6_addr *gwaddr);
 int ipv6_address_wrapper(char *ca_id, char *ip6, int prefixlen,char *option);
@@ -644,6 +697,8 @@
 #define VXLAN_SUCCESS	0
 #define VXLAN_ERROR	-1
 
+#define GENEVE_SUCCESS	0
+#define GENEVE_ERROR	-1
 
 #define	IP_VERSION_4_AND_6	0
 #define	IP_VERSION_6	6
Index: /branches/rel_apv_10_7/usr/click/lib/libip/ip.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libip/ip.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libip/ip.c	(working copy)
@@ -1638,6 +1638,86 @@
 	}
 }
 
+int ip_geneve_id2hw_id(nic_rec_t *nic_rec)
+{
+	char *ifname;
+	int i;
+	int notfound;
+	geneve_ip_t *geneve_p;
+	static int shm_geneve_id;
+
+	/* set in shared memory */
+	shm_geneve_id = shmget(GENEVE_SHM_KEY, sizeof(geneve_ip_t) * MAX_GENEVE, IPC_CREAT | SHM_W | SHM_R);
+	if (shm_geneve_id < 0) {
+		perror("shmget error\n");
+		return -1;
+	}
+
+	geneve_p = shmat(shm_geneve_id, 0, 0);
+	if (geneve_p == (void *)(-1)) {
+		perror("shmat error\n");
+		return -1;
+	}
+
+	notfound = 1;
+	for (i = 0; i < MAX_GENEVE; i++) {
+		if (strcmp(nic_rec->ca_id, geneve_p[i].ifname) != 0) {
+			continue;
+		}
+		notfound = 0;
+		break;
+	}
+
+	if (!notfound){
+		strcpy(nic_rec->hw_id, geneve_p[i].real_ifname);
+		strcpy(nic_rec->vhw_id, geneve_p[i].kni_ifname);
+		shmdt(geneve_p);
+		return IP_SUCCESS;
+	} else {
+		shmdt(geneve_p);
+		return IP_ERROR;
+	}
+}
+
+int ip_hw_id2geneve_id(char *hw_id, char *geneve_id)
+{
+	int i;
+	int notfound;
+	geneve_ip_t *geneve_p;
+	static int shm_geneve_id;
+
+	/* set in shared memory */
+	shm_geneve_id = shmget(GENEVE_SHM_KEY, sizeof(geneve_ip_t) * MAX_GENEVE, IPC_CREAT | SHM_W | SHM_R);
+	if (shm_geneve_id < 0) {
+		perror("shmget error\n");
+		return -1;
+	}
+
+	geneve_p = shmat(shm_geneve_id, 0, 0);
+	if (geneve_p == (void *)(-1)) {
+		perror("shmat error\n");
+		return -1;
+	}
+
+	notfound = 1;
+	for (i = 0; i < MAX_GENEVE; i++) {
+		if (strcmp(hw_id, geneve_p[i].real_ifname) != 0) {
+			continue;
+		}
+		notfound = 0;
+		break;
+	}
+
+	if (!notfound){
+		strcpy(geneve_id, geneve_p[i].ifname);
+		shmdt(geneve_p);
+		return IP_SUCCESS;
+	} else {
+		shmdt(geneve_p);
+		return IP_ERROR;
+	}
+}
+
 int hw_id_to_ifname(char *hw_id, char *ifname)
 {
 	int i;
@@ -1664,9 +1744,15 @@
 	if (IP_SUCCESS == ip_hw_id2bond_id(hw_id, ifname)){
 		return IP_SUCCESS;
 	}
+
 	if (IP_SUCCESS == ip_hw_id2vxlan_id(hw_id, ifname)){
 		return IP_SUCCESS;
 	}
+
+	if (IP_SUCCESS == ip_hw_id2geneve_id(hw_id, ifname)){
+		return IP_SUCCESS;
+	}
+
 	return IP_ERROR;
 }
 #if defined(__linux__)
@@ -1819,11 +1905,15 @@
 	if (IP_SUCCESS == ip_bond_id2hw_id(nic_rec)){
 		return IP_SUCCESS;
 	}
-	
+
 	if (IP_SUCCESS == ip_vxlan_id2hw_id(nic_rec)){
 		return IP_SUCCESS;
 	}
 
+	if (IP_SUCCESS == ip_geneve_id2hw_id(nic_rec)){
+		return IP_SUCCESS;
+	}
+
 	return IP_ERROR;
 }
 
Index: /branches/rel_apv_10_7/usr/click/lib/libip/sip.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libip/sip.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libip/sip.c	(working copy)
@@ -171,6 +171,9 @@
 /*vxlan_support*/
 #include <net/if_vxlan.h>
 
+/* geneve support */
+#include <net/if_geneve.h>
+
 #include <click/app/slb/slb_cli_util.h>
 #include <click/app/util/click_generic.h>
 #include <segment_utils.h>
@@ -507,7 +510,18 @@
 int  getvxlanif(const char *ifname, vxlan_ip_t *vxlan_ret);
 int  getvxlanif_num(int num, vxlan_ip_t *vxlan_ret); /*vxlan_support*/
 
-
+/* geneve support */
+int getgeneveif(const char *ifname, geneve_ip_t *);
+int getgeneveif_num(int num, geneve_ip_t *);
+void setgeneveipinfo(int, uint32_t, uint32_t);
+void setgeneveipv6info(int, char *, int);
+static geneve_ip_t  *get_global_geneve_config();
+static geneve_tun_t *get_global_geneve_tunnel_config();
+static int get_geneve_config_by_name(char *);
+static int get_geneve_tunnel_config_by_name(char *);
+static int geneve_ip_address(const char *, uint32_t, uint32_t);
+static int no_geneve_ip_address(const char *);
+static int no_geneve_ipv6_address(const char *);
 
 static int ipv6_does_vip_exist(char *ip6);
 static int ipv6_addr_sanity_check(char *ip6, int prefixlen);
@@ -1077,7 +1091,9 @@
 	BOND_ADAPTER *pba = NULL;
 	/* Link Aggregation, end */
 	vxlan_ip_t	*vxlan = NULL;
-	int 	vxlanid;
+	int     vxlanid;
+    geneve_ip_t  *geneve_p = NULL;
+    int     geneve_id;
 
 	if (strlen(ifname) <= 0){
 		printf("The name cannot be an empty string\n");
@@ -1192,6 +1208,19 @@
 	if (vxlan)
 		shmdt(vxlan);
 
+    /* check geneve */
+    geneve_p = get_global_geneve_config();
+    if (geneve_p) {
+        for (i = 0; i < MAX_GENEVE; i++) {
+            if (strcmp(ifname, geneve_p[i].ifname) == 0) {
+                printf("Error: geneve interface '%s' exists\n", ifname);
+                shmdt(geneve_p);
+                return -1;
+            }
+        }
+        shmdt(geneve_p);
+    }
+
 	/* Link Aggregation, lingx, 20050901 */
 	/* Check bond interface */
 	i = sizeof(pba);
@@ -3859,6 +3888,47 @@
 	return 0;
 }
 
+int
+localip_is_used_by_geneve_tunnel(uint32_t local_ip32, char *local_v6, int is_ipv6)
+{
+    geneve_tun_t *geneve_tun, geneve_tun_tmp;
+    int i;
+
+    geneve_tun = get_global_geneve_tunnel_config();
+    if(!geneve_tun) {
+        shmdt(geneve_tun);
+        return 1;
+    }
+
+    for (i = 0; i < MAX_GENEVE_TUNNEL; i++) {
+        geneve_tun_tmp = geneve_tun[i];
+
+        if (geneve_tun_tmp.valid == 0) {
+            continue;
+        }
+
+        if (geneve_tun_tmp.isipv6 != is_ipv6) {
+            continue;
+        }
+
+        if (is_ipv6) {
+            if (strcmp(geneve_tun_tmp.local_v6, local_v6) == 0) {
+                shmdt(geneve_tun);
+                return 1;
+            }
+        } else {
+            if (geneve_tun_tmp.local_ip32 == local_ip32) {
+                shmdt(geneve_tun);
+                return 1;
+            }
+        }
+    }
+
+    shmdt(geneve_tun);
+
+    return 0;
+}
+
 int get_ip_addr_by_ifname(const char *ifname, uint32_t *ipv4, char *ipv6)
 {
 	int i;
@@ -3872,7 +3942,7 @@
 
 	BOND_ADAPTER *pBondAdapter=NULL;
 	size_t nLen=sizeof(pBondAdapter);
-	
+
 	if (nic_init() != IP_SUCCESS) {
 		return -1;
 	}
@@ -3986,7 +4056,7 @@
 		perror("shmat");
 		return VXLAN_ERROR;
 	}
-	
+
 	for (i = 0; i < MAX_VXLAN; i++) {
 		if (vxlan_p[i].vni == vni) {
 			ret = show_vxlan_forwarding_kern(vni, mac, vxlan_p[i].vxl_gw_if);
@@ -4008,12 +4078,12 @@
 
 	struct in_addr addr;
 	char src[32], dst[32];
-	
+
 
 	/* set in shared memory */
 	shm_vxltun_id = shmget(VXLAN_TUN_SHM_KEY, sizeof(vxlan_tun_t) * MAX_VXLAN_TUNNEL, IPC_CREAT|SHM_W|SHM_R);
-   	if (shm_vxltun_id < 0) {
-	 	perror("shmget error\n");
+	if (shm_vxltun_id < 0) {
+		perror("shmget error\n");
 		return -1;
 	}
 
@@ -4029,7 +4099,7 @@
 			if (vxl_tun_tmp.valid == 0) {
 				continue;
 			}
-			
+
 			if (vxl_tun_tmp.isipv6) {
 				printf("vxlan tunnel %s %s %s\n", vxl_tun_tmp.tun_name, vxl_tun_tmp.local_v6, vxl_tun_tmp.remote_v6);
 			} else {
@@ -5880,6 +5950,204 @@
 }
 
 int
+geneve_ip_address(const char *ifname, uint32_t ip32, uint32_t mask32)
+{
+    int s;
+    geneve_ip_t geneve;
+    int geneve_num;
+    int changeIP=0;
+    struct ifaliasreq alq;
+    char *found_ip;
+    struct in_addr geneve_in4;
+    char geneve_ip4_str[INET_ADDRSTRLEN];
+
+    if (nic_init() != IP_SUCCESS) {
+        return IP_ERROR;
+    }
+
+    if (ip_does_vip_exist(ip32)) {
+        printf("Error: ip address is used by system interface\n");
+        return IP_ERROR;
+    }
+
+    if (getgeneveif(ifname, &geneve) != 0) {
+        return IP_NOTMINE;
+    }
+
+    if ((found_ip = newip_scan(ip32,mask32,1)) != NULL) {
+        printf("%s\n", found_ip);
+        return IP_ERROR;
+    }
+
+    /* Check same ip for LLB */
+    if (geneve.ip32 == ip32 && geneve.mask32 == mask32) {
+        return IP_ERROR;
+    }
+
+    if ((is_link_on() == 1) && geneve.ip32) {
+        printf("Unable to change geneve ip. Turn off llb link health first\n");
+        return IP_ERROR;
+    }
+
+    if ((ip32 & mask32) != (geneve.ip32 & geneve.mask32)) {
+        /* ip is changing from one subnet to another */
+        VipStatus *mvip;
+        struct in_addr ip;
+        ip.s_addr = 0;
+        mvip = get_vip_status( (char*)ifname, 0, 0, (void *)&ip);
+        if (mvip && mvip->status) {
+            printf("Error: Other configurations depend on the %s interface\n", ifname);
+            printf("Info: %s\n", (char *)mvip->users);
+            printf("To change the subnet, remove the dependent virtual ip first");
+            return IP_ERROR;
+        }
+    }
+
+    if (geneve.ip32 != 0) {
+        changeIP = 1;
+    }
+
+    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        printf("geneve_ip_address(): unable to create socket\n");
+        return IP_ERROR;
+    }
+
+    if (geneve.ip32 != 0) {
+        geneve_in4.s_addr = geneve.ip32 & geneve.mask32;
+        inet_ntop(AF_INET, &geneve_in4, geneve_ip4_str, INET_ADDRSTRLEN);
+        eroute_delete(make_eroute_name(eroute_name_buff, geneve_ip4_str));
+
+        strncpy(ifr.ifr_name, geneve.real_ifname, sizeof(ifr.ifr_name));
+        ifr.ifr_addr.sa_family = AF_INET;
+        ifr.ifr_addr.sa_len    = sizeof(struct sockaddr);
+        ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = geneve.ip32;
+        if (ioctl(s, SIOCDIFADDR, (caddr_t)&ifr) == -1) {
+            printf("geneve_ip_addr: Error deleting old IP\n");
+            goto error;
+        }
+
+        no_kni_ip_address(geneve.ip32, geneve.mask32, geneve.kni_ifname);
+    }
+
+    memset(&alq, 0, sizeof(alq));
+    strcpy(alq.ifra_name, geneve.real_ifname);
+    alq.ifra_addr.sa_family = AF_INET;
+    alq.ifra_addr.sa_len    = sizeof(struct sockaddr);
+    ((struct sockaddr_in *)(&alq.ifra_addr))->sin_addr.s_addr = ip32;
+    alq.ifra_mask.sa_len = sizeof(struct sockaddr);
+    ((struct sockaddr_in *)(&alq.ifra_mask))->sin_addr.s_addr = mask32;
+
+    if (ioctl(s, SIOCAIFADDR, (caddr_t)&alq) == -1) {
+        /* All of this nastiness is because ioctl may return -1, even if it */
+        /* succeeded.  IPv6 sucks ass.  */
+        if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) == -1 ||
+            ((struct sockaddr_in *)(&ifr.ifr_addr))->sin_addr.s_addr != ip32) {
+            printf("Error :setting interface IP address failed, please remove it first and try again\n");
+            goto error;
+        }
+    }
+
+    geneve_in4.s_addr = ip32 & mask32;
+    inet_ntop(AF_INET, &geneve_in4, geneve_ip4_str, INET_ADDRSTRLEN);
+    if (eroute_add(make_eroute_name(eroute_name_buff, geneve_ip4_str),
+        EROUTE_INTERFACE_PRIO, "0.0.0.0", 0, PORT_RANGE_MIN_PORT, PORT_RANGE_MAX_PORT,
+        geneve_ip4_str, mask32, PORT_RANGE_MIN_PORT, PORT_RANGE_MAX_PORT, 0, "0.0.0.0", EROUTE_DEFAULT_WEIGHT) != 0) {
+        goto error;
+    }
+
+    sscanf(geneve.real_ifname, "geneve%d", &geneve_num);
+    setgeneveipinfo(geneve_num, ip32, mask32);
+
+    kni_ip_address(ip32, mask32, geneve.kni_ifname);
+
+    close(s);
+
+    restore_route_ipv4(ip32, mask32, 0);
+
+#ifndef IP_MAIN
+    {
+        /* reset the primary ip address of va if necessary */
+        resetVaIpAddress((char *)ifname);
+    }
+#endif
+
+    if (changeIP && cli_interactive()) {
+        print_warning();
+    }
+
+    return IP_SUCCESS;
+
+error:
+    close(s);
+    return IP_ERROR;
+}
+
+static int
+no_geneve_ip_address(const char *ifname)
+{
+    int s;
+    geneve_ip_t geneve;
+    int geneve_num;
+    struct in_addr geneve_in4; /* for eroute */
+    char geneve_ip4_str[INET_ADDRSTRLEN];
+
+    if (getgeneveif(ifname, &geneve) != 0) {
+        return IP_NOTMINE;
+    }
+
+    if (!geneve.ip32) {
+        printf("IP information for '%s' not set\n", ifname);
+        return IP_ERROR;
+    }
+
+    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        printf("no_geneve_ip_address(): unable to create socket\n");
+        return IP_ERROR;
+    }
+
+    /* Set the interface as down */
+    strncpy(ifr.ifr_name, geneve.real_ifname, sizeof(ifr.ifr_name));
+    if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) {
+        perror("Error getting interface flags");
+        goto error;
+    }
+
+    /* Remove the IP address */
+    geneve_in4.s_addr = geneve.ip32 & geneve.mask32;
+    inet_ntop(AF_INET, &geneve_in4, geneve_ip4_str, INET_ADDRSTRLEN);
+    if (eroute_delete(make_eroute_name(eroute_name_buff, geneve_ip4_str)) != 0) {
+        if (cli_interactive()) {
+            printf("Unable to remove a routing policy corresponding this address\n");
+        }
+        goto error;
+    }
+    ifr.ifr_addr.sa_family = AF_INET;
+    ifr.ifr_addr.sa_len    = sizeof(struct sockaddr);
+
+    if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) == -1) {
+        perror("IP information for '%s' not set\n");
+        goto error;
+    }
+
+    if (ioctl(s, SIOCDIFADDR, (caddr_t)&ifr) == -1) {
+        perror("Error deleting IP");
+        goto error;
+    }
+
+    no_kni_ip_address(geneve.ip32, geneve.mask32, geneve.kni_ifname);
+
+    sscanf(geneve.real_ifname, "geneve%d", &geneve_num);
+    setgeneveipinfo(geneve_num, 0, 0);
+
+    close(s);
+    return IP_SUCCESS;
+
+error:
+    close(s);
+    return IP_ERROR;
+}
+
+int
 vxlan_ip_address(const char *ifname, uint32_t ip32, uint32_t mask32)
 {
 	int s;
@@ -7502,12 +7770,16 @@
     	i = bond_ip_address(ca_id, ip32, mask32, overlap_flag, segment_name);
 		if (i == IP_SUCCESS || i == IP_ERROR || i == IP_BUSY)
 			return i;    	
-    	/*Link Aggregation,end*/
+		/*Link Aggregation,end*/
 
 		i = vxlan_ip_address(ca_id, ip32, mask32);
 		if (i == IP_SUCCESS || i == IP_ERROR || i == IP_BUSY)
 			return i;
-    	
+
+        i = geneve_ip_address(ca_id, ip32, mask32);
+        if (i == IP_SUCCESS || i == IP_ERROR || i == IP_BUSY)
+            return i;
+
 		/* Not inside, outside, mnet, vlan or bond?  Error out */
 		printf("Unknown interface '%s'\n",ca_id);
 		return IP_ERROR;
@@ -8216,13 +8488,13 @@
     static int shm_vxlan_id;
     vlan_ip_t* vlan_p;
     vxlan_ip_t* vxlan_p;
+	geneve_ip_t* geneve_p;
     /*Link Aggregation,beisf,20050829*/
     BOND_ADAPTER *pBondAdapter=NULL;
     size_t nLen=sizeof(pBondAdapter);
     char sCaName[BOND_ADAPTER_CA_NAME_LEN];
     /*Link Aggregation,end*/
 
-	
     if (nic_init() != IP_SUCCESS) {
 		return IP_ERROR;
     }
@@ -8292,52 +8564,73 @@
 	}
 
 	for ( i = 0; i < MAX_VXLAN; i++) {
-	    if (vxlan_p[i].vni == 0)
+		if (vxlan_p[i].vni == 0)
 			continue;
-	    if (vxlan_p[i].ip32) {
-	   	 addr.s_addr = vxlan_p[i].ip32;
-	    	printf("ip address \"%s\" %s", vxlan_p[i].ifname, inet_ntoa(addr));
-	    	addr.s_addr = vxlan_p[i].mask32;
-	    	printf(" %s\n", inet_ntoa(addr));
-	    }
-      	    if (vxlan_p[i].v6[0]) {
-		printf("ip address \"%s\" %s %d\n", vxlan_p[i].ifname, vxlan_p[i].v6, vxlan_p[i].prefixlen);
-          }
+		if (vxlan_p[i].ip32) {
+			addr.s_addr = vxlan_p[i].ip32;
+			printf("ip address \"%s\" %s", vxlan_p[i].ifname, inet_ntoa(addr));
+			addr.s_addr = vxlan_p[i].mask32;
+			printf(" %s\n", inet_ntoa(addr));
+		}
+		if (vxlan_p[i].v6[0]) {
+			printf("ip address \"%s\" %s %d\n", vxlan_p[i].ifname, vxlan_p[i].v6, vxlan_p[i].prefixlen);
+		}
 	}
 
-        shmdt(vxlan_p);
+		shmdt(vxlan_p);
+	}
+
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
     }
 
+	for ( i = 0; i < MAX_GENEVE; ++i) {
+		if (geneve_p[i].vni == 0)
+			continue;
+		if (geneve_p[i].ip32) {
+			addr.s_addr = geneve_p[i].ip32;
+			printf("ip address \"%s\" %s", geneve_p[i].ifname, inet_ntoa(addr));
+			addr.s_addr = geneve_p[i].mask32;
+			printf(" %s\n", inet_ntoa(addr));
+		}
+		if (geneve_p[i].v6[0]) {
+			printf("ip address \"%s\" %s %d\n", geneve_p[i].ifname, geneve_p[i].v6, geneve_p[i].prefixlen);
+		}
+	}
+
+	shmdt(geneve_p);
+
     /* MNET */
-    shm_mnet_id = shmget(MNET_SHM_KEY, sizeof(mnet_ip_t) * MAX_MNET, IPC_CREAT|SHM_W|SHM_R);     
+    shm_mnet_id = shmget(MNET_SHM_KEY, sizeof(mnet_ip_t) * MAX_MNET, IPC_CREAT|SHM_W|SHM_R);
 
     if (shm_mnet_id >= 0) {
-	mp = (mnet_ip_t *) shmat(shm_mnet_id, 0, 0);
-	if ((long)mp < 0) {
-	    printf("shmat error\n");
-	    return -1;
-	}
-
-	for (i = 0; i < MAX_MNET; i++){
-	    if (mp[i].ip32) {
-			addr.s_addr = mp[i].ip32;
-			printf("ip address \"%s\" %s ",mp[i].ifname, inet_ntoa(addr));
-			addr.s_addr = mp[i].mask32;
-			if(!is_overlap_ip(mp[i].ip32)){
-				printf("%s\n", inet_ntoa(addr));
-			} else {
-				printf("%s overlap\n", inet_ntoa(addr));
-			} 
+		mp = (mnet_ip_t *) shmat(shm_mnet_id, 0, 0);
+		if ((long)mp < 0) {
+			printf("shmat error\n");
+			return -1;
 		}
-		if (mp[i].v6[0]) {
-			if(!is_overlap_ip6(mp[i].v6)){
-				printf("ip address \"%s\" %s %d\n", mp[i].ifname, mp[i].v6, mp[i].prefixlen);
-			}else {
-				printf("ip address \"%s\" %s %d overlap\n", mp[i].ifname, mp[i].v6, mp[i].prefixlen);
+
+		for (i = 0; i < MAX_MNET; ++i){
+			if (mp[i].ip32) {
+				addr.s_addr = mp[i].ip32;
+				printf("ip address \"%s\" %s ",mp[i].ifname, inet_ntoa(addr));
+				addr.s_addr = mp[i].mask32;
+				if(!is_overlap_ip(mp[i].ip32)){
+					printf("%s\n", inet_ntoa(addr));
+				} else {
+					printf("%s overlap\n", inet_ntoa(addr));
+				} 
+			}
+			if (mp[i].v6[0]) {
+				if(!is_overlap_ip6(mp[i].v6)){
+					printf("ip address \"%s\" %s %d\n", mp[i].ifname, mp[i].v6, mp[i].prefixlen);
+				}else {
+					printf("ip address \"%s\" %s %d overlap\n", mp[i].ifname, mp[i].v6, mp[i].prefixlen);
+				}
 			}
 		}
-	}
-	shmdt(mp);
+		shmdt(mp);
     }
 
 	/*Link Aggregation,beisf,20050829*/
@@ -9298,6 +9591,10 @@
 			printf("The IP of %s is being used. Delete the VXLAN tunnel bound to %s first.\n", ifname, ifname);
 			return 0;
 		}
+        if (localip_is_used_by_geneve_tunnel(ipv4, ipv6, isipv6)) {
+            printf("The IP of %s is being used. Delete the GENEVE tunnel bound to %s first.\n", ifname, ifname);
+            return 0;
+        }
 	}
 
 	if(isipv6) {
@@ -9842,10 +10139,17 @@
 		ret = no_vxlan_ip_address(ca_id);
 		if (ret == IP_SUCCESS) {
 			goto PRT_WARN;
-		} else if (ret != IP_NOTMINE) { 
+		} else if (ret != IP_NOTMINE) {
 			return ret;
 		}
-		
+
+        ret = no_geneve_ip_address(ca_id);
+        if (ret == IP_SUCCESS) {
+            goto PRT_WARN;
+        } else if (ret != IP_NOTMINE) {
+            return ret;
+        }
+
 		printf("Unknown interface '%s'\n", ca_id);
 		return IP_ERROR;
 		/*Link aggregation,beisf,20050829*/
@@ -11610,6 +11914,7 @@
 	static int shm_vxlan_id;
 	vlan_ip_t* vlan_p = NULL;
 	vxlan_ip_t* vxlan_p = NULL;
+	geneve_ip_t* geneve_p = NULL;
 	BOND_ADAPTER *pBondAdapter = NULL;
 	size_t nLen=sizeof(pBondAdapter);
 	char sCaName[BOND_ADAPTER_CA_NAME_LEN] = {0};
@@ -11690,8 +11995,26 @@
 		shmdt(vxlan_p);
 	}
 
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+	for (i = 0; i < MAX_GENEVE; ++i) {
+		if (geneve_p[i].vni == 0) {
+			continue;
+		}
+
+		if (strcmp(ether_id, geneve_p[i].ifname) == 0) {
+			snprintf(geneve_p[i].geneve_info, CA_INFO, "%s", description);
+			goto END;
+		}
+	}
+
+	shmdt(geneve_p);
+
 	printf("Invalid interface name.\n");
-	
+
 	return -1;
 
 END:
@@ -11703,6 +12026,10 @@
 		shmdt(vxlan_p);
 	}
 
+	if (geneve_p != NULL) {
+		shmdt(geneve_p);
+	}
+
 	return 0;
 }
 
@@ -14638,7 +14965,8 @@
 	int type = SHOW_INTF_UNKONW;
 	vlan_ip_t vlan;
 	vxlan_ip_t vxlan;
-	
+	geneve_ip_t geneve;
+
 	if (nic_init() != IP_SUCCESS) {
 		return IP_ERROR;
 	}
@@ -14653,7 +14981,10 @@
 	} else if (getvxlanif(ca_id, &vxlan) == 0) {
 		type = SHOW_INTF_VXLAN;
 		ifnum = vxlan.num;
-	} else {
+	} else if (getgeneveif(ca_id, &geneve) == 0) {
+		type = SHOW_INTF_GENEVE;
+		ifnum = geneve.num;
+    } else {
 		type = SHOW_INTF_NIC;
 
 		for (ifnum = 0; ifnum < *total_nic; ifnum++) {
@@ -14681,6 +15012,7 @@
 		case SHOW_INTF_BOND:
 		case SHOW_INTF_VLAN:
 		case SHOW_INTF_VXLAN:
+		case SHOW_INTF_GENEVE:
 		case SHOW_INTF_NIC:
 			return do_showif_part_intf(type, ca_id, ifnum);
 			break;
@@ -14795,7 +15127,9 @@
 				type = SHOW_INTF_VLAN;
 			} else if (sscanf(name, "vxlan%d", &ifnum) == 1) {
 				type = SHOW_INTF_VXLAN;
-			}else {
+			} else if (sscanf(name, "geneve%d", &ifnum) == 1) {
+                type = SHOW_INTF_GENEVE;
+            } else {
 				type = SHOW_INTF_UNKONW;
 				ifnum = SHOW_INTF_MAGICNO;
 			}
@@ -14915,11 +15249,21 @@
 			} else {
 				continue;
 			}
-		}
-		
+		} else if (type == SHOW_INTF_GENEVE) {
+            if ( sscanf(name, "geneve%d", &inum_cmp) == 1) {
+                if (ifnum != inum_cmp) {
+                    continue;
+                } else {
+                    finished = 1;
+                }
+            } else {
+                continue;
+            }
+        }
+
 		do_showif_status(addrcount, sdl, ifam, type, ifnum);
 	}
-	
+
 	free(buf);
 
 	return(IP_SUCCESS);
@@ -14952,6 +15296,7 @@
 
 	vlan_ip_t vlan= {0};
 	vxlan_ip_t vxlan = {0};
+	geneve_ip_t geneve = {0};
 	char bond_name[BOND_ADAPTER_CA_NAME_LEN];
 	char ca_id[CA_NLEN];
 	char ether_id[CA_ETHERLEN];
@@ -14993,9 +15338,16 @@
 		if (vxlan.vni == 0) {
 			return;
 		}
+	} else if (type == SHOW_INTF_GENEVE) {
+		if (getgeneveif_num(ifnum, &geneve) != 0) {
+			return;
+		}
+		if (geneve.vni == 0) {
+			return;
+		}
 	} else if (type == SHOW_INTF_BOND) {
 		printf("\n");
-		bzero(bond_name, sizeof(bond_name)); 
+		bzero(bond_name, sizeof(bond_name));
 		if (getbondif_num(ifnum, bond_name) == 0) {
 			do_showif_status_bond(bond_name, ifam, addrcount);
 			return;
@@ -15040,6 +15392,13 @@
 		printf("\n%s(vxlan%d): ", vxlan.ifname, vxlan_idx+1);
 	}
 
+	if (type == SHOW_INTF_GENEVE) {
+		/* geneve index starts from 1 */
+		int geneve_idx = 0;
+		sscanf(geneve.real_ifname, "geneve%d", &geneve_idx);
+		printf("\n%s(geneve%d): ", geneve.ifname, geneve_idx+1);
+	}
+
 	/* 2.ouput: flags metric mtu */
 	printb("flags", (uint32_t)sflags, IFFBITS);
 	if (metric) {
@@ -15057,9 +15416,9 @@
 	ether_status(s, (struct rt_addrinfo *)(void *)sdl);
 	/* output MAC addresses of the MAC proxy */
 	mac_proxy_status(name, (sdl->sdl_type == IFT_ETHER) ? "\t      " : "\t       ");
-	
+
 	/* 5.ouput: media status*/
-	if (type != SHOW_INTF_VXLAN) {
+	if (type != SHOW_INTF_VXLAN && type != SHOW_INTF_GENEVE) {
 		media_status(s, NULL, type, nic_ca_p);
 	}
 
@@ -15089,6 +15448,25 @@
 			close(s);
 			return;
 		}
+	} else if (type == SHOW_INTF_GENEVE) {
+		for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; ++i) {
+			if (geneve.geneve_tun[i] != MAX_GENEVE_TUNNEL) {
+				++count;
+			}
+		}
+		printf("\tgeneve : %d tunnel list:\n", count);
+
+		if (NULL == ca_ptr) {
+			printf("ca_ptr is null\n");
+			close(s);
+			return;
+		}
+
+		ifn_p = ca_ptr->ifnodes[ifnum + CAFW_GENEVE_OFFSET];
+		if (NULL == ifn_p) {
+			close(s);
+			return;
+		}
 	} else {
 		ifn_p = ca_ptr->ifnodes[ifnum];
 	}
@@ -15105,6 +15483,10 @@
 		if (strlen(vxlan.vxlan_info)) {
 			printf("\tdescription: %s\n", vxlan.vxlan_info);
 		}
+	} else if (type == SHOW_INTF_GENEVE) {
+		if (strlen(geneve.geneve_info)) {
+			printf("\tdescription: %s\n", geneve.geneve_info);
+		}
 	}
 
 	/* 7.ouput: webwall status*/
@@ -17401,6 +17783,7 @@
 	BOND_ADAPTER *pBondAdapter=NULL;
 	size_t nLen=sizeof(pBondAdapter);
 	vxlan_ip_t *vxlan_p;
+	geneve_ip_t *geneve_p;
 
 	if (nic_init() != IP_SUCCESS) {
 		return -1;
@@ -17484,13 +17867,32 @@
 			}
 
 			if ((vxlan_p[i].ip32 & vxlan_p[i].mask32) == (gw & vxlan_p[i].mask32)) {
-				shmdt(vlan_p);
+				shmdt(vxlan_p);
 				return 0;
 			}
 		}
-		shmdt(vlan_p);
+		shmdt(vxlan_p);
+	}
+
+	/* geneve */
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
     }
 
+	for (i = 0; i < MAX_GENEVE; i++) {
+		if (strncmp(geneve_p[i].real_ifname, "geneve", 6) || geneve_p[i].ip32 == 0) {
+			continue;
+		}
+
+		if ((geneve_p[i].ip32 & geneve_p[i].mask32) == (gw & geneve_p[i].mask32)) {
+			shmdt(geneve_p);
+			return 0;
+		}
+	}
+
+	shmdt(geneve_p);
+
 	return -1;
 }
 
@@ -17502,6 +17904,8 @@
 	int i;
 	static int shm_vlan_id;
 	vlan_ip_t* vlan_p;
+	static int shm_geneve_id;
+	geneve_ip_t* geneve_p;
 	BOND_ADAPTER *pBondAdapter=NULL;
 	size_t nLen=sizeof(pBondAdapter);
 	struct in6_addr addr1, net1, net2;
@@ -17601,6 +18005,36 @@
 		}
 	}
 
+	/* geneve */
+	shm_geneve_id = shmget(GENEVE_SHM_KEY, sizeof(geneve_ip_t) * MAX_GENEVE, 0);
+	if (shm_geneve_id >= 0) {
+		geneve_p = (geneve_ip_t *)shmat(shm_geneve_id, 0, 0);
+		if ((long)geneve_p < 0) {
+			printf("shmat geneve error\n");
+			return -1;
+		}
+
+		for (i = 0; i < MAX_GENEVE; i++) {
+			if (geneve_p[i].v6[0] == '\0') {
+				continue;
+			}
+
+			if(inet_pton(AF_INET6, geneve_p[i].v6, &addr1) != 1) {
+				continue;
+			}
+
+			ipv6_get_net(&addr1, geneve_p[i].prefixlen, &net1);
+			ipv6_get_net(&gw, geneve_p[i].prefixlen, &net2);
+
+			if (IN6_ARE_ADDR_EQUAL(&net1, &net2)) {
+				shmdt(geneve_p);
+				return 0;
+			}
+		}
+
+		shmdt(geneve_p);
+	}
+
 	return -1;
 }
 
@@ -22238,6 +22672,45 @@
 }
 
 static int
+no_geneve_ipv6_address(const char *ifname)
+{
+    geneve_ip_t geneve;
+    int geneve_num;
+    struct in6_addr dip_in6, mask_in6;
+    char geneve_ip6_str[INET6_ADDRSTRLEN];
+
+    if (getgeneveif(ifname, &geneve) != 0) {
+        return IP_NOTMINE;
+    }
+
+    if (!geneve.v6[0]) {
+        printf("IPv6 information for '%s' not set\n", ifname);
+        return IP_ERROR;
+    }
+
+    /* Remove the IP address */
+    masklen2ip6(geneve.prefixlen, &mask_in6);
+    inet_pton(AF_INET6, geneve.v6, &dip_in6);
+    ipv6_get_netaddr(&dip_in6, &mask_in6, &dip_in6);
+    inet_ntop(AF_INET6, &dip_in6, geneve_ip6_str, INET6_ADDRSTRLEN);
+    if (eroute_delete(make_eroute_name(eroute_name_buff, geneve_ip6_str)) != 0) {
+        if (cli_interactive()) {
+            printf("Unable to remove a routing policy corresponding this address\n");
+        }
+        return IP_ERROR;
+    }
+
+    if (geneve.v6[0]) {
+        ipv6_delete_address(geneve.real_ifname, geneve.v6, geneve.prefixlen);
+    }
+
+    sscanf(geneve.real_ifname, "geneve%d", &geneve_num);
+    setgeneveipv6info(geneve_num, "\0", 0);
+
+    return IP_SUCCESS;
+}
+
+static int
 mnet_ipv6_address(const char *ca_id, char *ip6, int prefixlen, int overlap_flag)
 {
     static int shm_mnet_id;
@@ -22859,6 +23332,107 @@
 	return IP_ERROR;
 }
 
+static int
+geneve_ipv6_address(const char *ifname, char *ip6, int prefixlen)
+{
+    int ret;
+    int changeIP = 0;
+    char *found_ip;
+    struct in6_addr geneve_in6, mask_in6;
+    char geneve_ip6_str[INET6_ADDRSTRLEN];
+    int geneve_num;
+    geneve_ip_t geneve;
+
+    if (nic_init() != IP_SUCCESS) {
+        return IP_ERROR;
+    }
+
+    if (ipv6_does_vip_exist(ip6)) {
+        printf("Error: ip address is used by system interface\n");
+        return IP_ERROR;
+    }
+
+    if (getgeneveif(ifname, &geneve) != 0) {
+        return IP_NOTMINE;
+    }
+
+    if ((found_ip = newip6_scan(ip6, prefixlen, 0)) != NULL) {
+        printf("%s\n", found_ip);
+        return IP_ERROR;
+    }
+
+    ret = ipv6_addr_sanity_check(ip6, prefixlen);
+    if (ret == IP_ERROR) {
+        return ret;
+    }
+
+    /* Check same ip */
+    if (strcmp(geneve.v6, ip6) == 0 && geneve.prefixlen == prefixlen) {
+        return IP_ERROR;
+    }
+
+    if ((is_link_on() == 1) && geneve.v6[0]) {
+        printf("Unable to change geneve ip. Turn off llb link health first\n");
+        return(IP_ERROR);
+    }
+
+    if (!ipv6_net_eq(ip6, prefixlen, geneve.v6, geneve.prefixlen)) {
+        /* ip is changing from one subnet to another */
+        VipStatus *mvip;
+        struct in6_addr in6;
+        in6 = in6addr_any;
+        mvip = get_vip_status( (char*)ifname, 0, 1, (void *)&in6);
+        if (mvip && mvip->status) {
+            printf("Error: Other configurations depend on the %s interface\n", ifname);
+            printf("Info: %s\n", (char *)mvip->users);
+            printf("To change the subnet, remove the dependent virtual ip first");
+            return(IP_ERROR);
+        }
+    }
+
+    if (geneve.v6[0]) {
+        changeIP = 1;
+    }
+
+    /* Delete the old ip*/
+    if (geneve.v6[0] != 0) {
+        ipv6_delete_address(geneve.real_ifname, geneve.v6, geneve.prefixlen);
+    }
+
+    /* setup new ip */
+    ret = ipv6_new_address(geneve.real_ifname, ip6, prefixlen);
+    if (ret == IP_ERROR) {
+        goto error;
+    }
+
+    masklen2ip6(prefixlen, &mask_in6);/*mask6*/
+    inet_pton(AF_INET6, ip6, &geneve_in6);
+    ipv6_get_netaddr(&geneve_in6, &mask_in6, &geneve_in6);
+    inet_ntop(AF_INET6, &geneve_in6, geneve_ip6_str, INET6_ADDRSTRLEN);
+    if (eroute_add(make_eroute_name(eroute_name_buff, geneve_ip6_str),
+            EROUTE_INTERFACE_PRIO, "::", 0, PORT_RANGE_MIN_PORT, PORT_RANGE_MAX_PORT,
+            geneve_ip6_str, prefixlen, PORT_RANGE_MIN_PORT, PORT_RANGE_MAX_PORT, 0, "::", EROUTE_DEFAULT_WEIGHT) != 0) {
+        goto error;
+    }
+
+    sscanf(geneve.real_ifname, "geneve%d", &geneve_num);
+    setgeneveipv6info(geneve_num, ip6, prefixlen);
+
+#ifndef IP_MAIN
+    {
+        /* reset the primary ip address of va if necessary */
+        resetVaIpAddress((char *)ifname);
+    }
+#endif
+    if (changeIP && cli_interactive()) {
+        print_warning();
+    }
+
+    return IP_SUCCESS;
+
+error:
+    return IP_ERROR;
+}
 
 int
 ipv6_address_wrapper(char *ca_id, char *ip6, int prefixlen,char *option)
@@ -22991,6 +23565,10 @@
 		if (i == IP_SUCCESS || i == IP_ERROR || i == IP_BUSY)
 			return i;
 
+		i = geneve_ipv6_address(ca_id, ip6, prefixlen);
+		if (i == IP_SUCCESS || i == IP_ERROR || i == IP_BUSY)
+			return i;
+
 		CLI_PRINTF(("Unknown interface \"%s\"\n", ca_id));
 		return IP_ERROR;
 	} else {
@@ -23191,10 +23769,17 @@
 		ret=no_vxlan_ipv6_address(ca_id);
 		if (ret == IP_SUCCESS) {
 			goto PRT_WARN;
-		}else if(ret==IP_ERROR || ret==IP_BUSY) { 
+		}else if(ret==IP_ERROR || ret==IP_BUSY) {
 			return ret;
 		}
-		
+
+		ret = no_geneve_ipv6_address(ca_id);
+		if (ret == IP_SUCCESS) {
+			goto PRT_WARN;
+		}else if (ret == IP_ERROR || ret == IP_BUSY) {
+			return ret;
+		}
+
 		printf("Unknown interface '%s'\n", ca_id);
 		return IP_ERROR;
 		/*Link aggregation,beisf,20050829*/
@@ -27670,3 +28255,1667 @@
 	}
 }
 
+/* GENEVE begin */
+
+int
+getgeneveif(const char *ifname, geneve_ip_t *geneve_ret)
+{
+    int i;
+    int notfound = 1;
+    geneve_ip_t *geneve_p;
+
+    geneve_p = get_global_geneve_config();
+
+    for (i = 0; i < MAX_GENEVE; i++) {
+        if (strcmp(ifname, geneve_p[i].ifname) != 0) {
+            continue;
+        }
+
+        *geneve_ret = geneve_p[i];
+        notfound = 0;
+        break;
+    }
+
+    shmdt(geneve_p);
+
+    return notfound;
+}
+
+int
+getgeneveif_num(int num, geneve_ip_t *geneve_ret)
+{
+    geneve_ip_t *geneve_p;
+
+    geneve_p = get_global_geneve_config();
+
+    *geneve_ret = geneve_p[num];
+    shmdt(geneve_p);
+
+    return 0;
+}
+
+void
+setgeneveipinfo(int geneve_num, uint32_t ip, uint32_t nmask)
+{
+    geneve_ip_t *geneve_p;
+    int isipv6 = 0;
+
+    geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return;
+    }
+
+    if (geneve_p[geneve_num].ip32) {
+        vipstat_delete_vip(&geneve_p[geneve_num].ip32, sizeof(geneve_p[geneve_num].ip32), isipv6);
+    }
+
+    if (ip) {
+        vipstat_new_vip(&ip, sizeof(ip), isipv6);
+    }
+
+    geneve_p[geneve_num].ip32 = ip;
+    geneve_p[geneve_num].mask32 = nmask;
+    shmdt(geneve_p);
+}
+
+void
+setgeneveipv6info(int geneve_num, char *ip6, int prefixlen)
+{
+    geneve_ip_t *geneve_p;
+    struct in6_addr in6;
+    int isipv6 = 1;
+
+    geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return;
+    }
+
+    if (geneve_p[geneve_num].v6[0] != '\0') {
+        inet_pton(AF_INET6, geneve_p[geneve_num].v6, &in6);
+        vipstat_delete_vip(&in6, sizeof(in6), isipv6);
+    }
+
+    if (ip6){
+        inet_pton(AF_INET6, ip6, &in6);
+        vipstat_new_vip(&in6, sizeof(in6), isipv6);
+    }
+
+    strlcpy(geneve_p[geneve_num].v6, ip6, INET6_ADDRSTRLEN);
+    geneve_p[geneve_num].prefixlen = prefixlen;
+    shmdt(geneve_p);
+}
+
+static int
+geneve_check_tunnel_ip(char *localip, char *dstip)
+{
+    if (strcmp(localip, "0.0.0.0") == 0) {
+        printf("Local IP address cannot 0.0.0.0\n");
+        return -1;
+    }
+
+    if (!ip_is_intf_ip(localip)) {
+        printf("Local IP address does not exist.\n");
+        return -1;
+    } else if (ip_is_sys_vip(localip)) {
+        printf("Local IP cannot be VIP.\n");
+        return -1;
+    }
+
+    if (ip_is_intf_ip(dstip) || ip_is_sys_vip(dstip)) {
+        printf("The remote IP conflicts with the local IP.\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+geneve_ip_str_convert(char *ip_str, struct in_addr *ip, struct in6_addr *ip6)
+{
+    int isipv6 = -1;
+
+    if(strstr(ip_str, ".") != NULL) {
+        isipv6 = 0;
+        if (inet_aton(ip_str, ip) != 1) {
+            return -1;
+        }
+    } else {
+        isipv6 = 1;
+        if (inet_pton(AF_INET6, ip_str, ip6) != 1) {
+            return -1;
+        }
+    }
+
+    return isipv6;
+}
+
+static char *
+geneve_vni_scan(int vni)
+{
+    char ifname[CA_NLEN];
+    geneve_ip_t *geneve = NULL;
+    int i, geneve_id;
+    char *retval = NULL;
+
+    geneve_id = shmget(GENEVE_SHM_KEY, sizeof(geneve_ip_t) * MAX_GENEVE, IPC_CREAT | SHM_W | SHM_R);
+    if (geneve_id > 0) {
+        geneve = (geneve_ip_t *)shmat(geneve_id, 0, 0);
+    }
+
+    if ((long)geneve == -1) {
+        geneve = NULL;
+    }
+
+    if (geneve && !retval) {
+        for (i = 0; i < MAX_GENEVE; i++) {
+            if (vni == geneve[i].vni) {
+                retval = geneve[i].ifname;
+                sprintf(ifname ,"The VNI number is already used by the GENEVE interface '%s'.\n", retval);
+                retval = ifname;
+                printf("%s", retval);
+                break;
+            }
+        }
+    }
+
+    if (geneve) {
+        shmdt(geneve);
+    }
+
+    return retval;
+}
+
+static int
+find_free_geneve()
+{
+    int i, geneve_num = -1, shm_geneve_id;
+    geneve_ip_t *geneve_p;
+    size_t len;
+
+    geneve_p = get_global_geneve_config();
+
+    for (i = 0; i < MAX_GENEVE; i++) {
+        if (strncmp(geneve_p[i].real_ifname, "geneve", 6)) {
+            geneve_num = i;
+            break;
+        }
+    }
+
+    shmdt(geneve_p);
+
+    return geneve_num;
+}
+
+static int
+find_free_geneve_tunnel(char *tun_name, int *exsit)
+{
+    int i, tunnel_num = -1, shm_geneve_tunid;
+    geneve_tun_t *geneve_tun;
+
+    geneve_tun = get_global_geneve_tunnel_config();
+
+    for (i = 0; i < GENEVE_MAX_TUNNEL; i++) {
+        if (!strncmp(tun_name, geneve_tun[i].tun_name, strlen(tun_name))) {
+            tunnel_num = i;
+            shmdt(geneve_tun);
+            *exsit = 1;
+            return tunnel_num;
+        }
+    }
+
+    for (i = 0; i < GENEVE_MAX_TUNNEL; i++) {
+        if (geneve_tun[i].valid == 0) {
+            tunnel_num = i;
+            break;
+        }
+    }
+
+    shmdt(geneve_tun);
+
+    return tunnel_num;
+}
+
+static int
+set_geneve_dev_vni(const char *ifname, int vni)
+{
+    struct ifgenevecmd cmd;
+    struct ifdrv ifd;
+    int s;
+
+    bzero(&cmd, sizeof(cmd));
+    cmd.cmd_vni = vni;
+
+    bzero(&ifd, sizeof(ifd));
+    strlcpy(ifd.ifd_name, ifname, sizeof(ifd.ifd_name));
+    ifd.ifd_cmd = GENEVE_CMD_SET_VNI;
+    ifd.ifd_len = sizeof(struct ifgenevecmd);
+
+    memcpy(ifd.ifd_data, (void*)&cmd, sizeof(struct ifgenevecmd));
+
+    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        return -1;
+    }
+
+    if(-1 == ioctl(s, SIOCSDRVSPEC, &ifd)) {
+        perror("Error setting geneve vni");
+        return 1;
+    }
+
+    return 0;
+}
+
+static geneve_ip_t*
+get_global_geneve_config()
+{
+    geneve_ip_t *geneve_p;
+    int shm_geneve_id;
+
+    /* set in shared memory */
+    shm_geneve_id = shmget(GENEVE_SHM_KEY, sizeof(geneve_ip_t) * MAX_GENEVE, IPC_CREAT | SHM_W | SHM_R);
+    if (shm_geneve_id < 0) {
+        printf("GENEVE: shmget error, return %d.\n", shm_geneve_id);
+        return NULL;
+    }
+
+    geneve_p = shmat(shm_geneve_id, 0, 0);
+    if (geneve_p == (void *)(-1)) {
+        perror("GENEVE: shmat.\n");
+        return NULL;
+    }
+
+    return geneve_p;
+}
+
+static int
+get_geneve_config_by_name(char *geneve_name)
+{
+    geneve_ip_t *geneve_p;
+    int i;
+
+    geneve_p = get_global_geneve_config();
+    if (geneve_p) {
+        for (i = 0; i < MAX_GENEVE; i++) {
+            if (!strcmp(geneve_name, geneve_p[i].ifname)) {
+                return i;
+            }
+        }
+    }
+
+    shmdt(geneve_p);
+
+    return -1;
+}
+
+static void
+set_global_geneve_config(char *name, int num, int vni)
+{
+    int i;
+    char ifname[CA_NLEN];
+    geneve_ip_t *geneve_p;
+
+    geneve_p = get_global_geneve_config();
+
+    if(geneve_p) {
+        memset(&geneve_p[num], 0, sizeof(geneve_ip_t));
+        geneve_p[num].num = num;
+        geneve_p[num].vni = vni;
+        strncpy(geneve_p[num].ifname, name, sizeof(geneve_p[num].ifname));
+        snprintf(geneve_p[num].real_ifname, CA_NLEN, "geneve%u", num);
+        snprintf(geneve_p[num].kni_ifname, CA_NLEN, "atcp_geneve%u", num);
+
+        for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; i++) {
+            geneve_p[num].geneve_tun[i] = MAX_GENEVE_TUNNEL;
+        }
+    }
+
+    shmdt(geneve_p);
+}
+
+static geneve_tun_t*
+get_global_geneve_tunnel_config()
+{
+    geneve_tun_t *geneve_tun;
+    int shm_geneve_tunid;
+
+    /* set in shared memory */
+    shm_geneve_tunid = shmget(GENEVE_TUN_SHM_KEY, sizeof(geneve_tun_t) * GENEVE_VNI_MAX_TUNNEL, IPC_CREAT | SHM_W | SHM_R);
+    if (shm_geneve_tunid < 0) {
+        printf("GENEVE: shmget error, return %d.\n", shm_geneve_tunid);
+        return NULL;
+    }
+
+    geneve_tun = shmat(shm_geneve_tunid, 0, 0);
+    if (geneve_tun == (void *)(-1)) {
+        perror("GENEVE: shmat.\n");
+        return NULL;
+    }
+
+    return geneve_tun;
+}
+
+static int
+get_geneve_tunnel_config_by_name(char *tun_name)
+{
+    geneve_tun_t *geneve_tun = get_global_geneve_tunnel_config();
+    int i;
+
+    if (geneve_tun) {
+        for (i = 0; i < GENEVE_MAX_TUNNEL; i++) {
+            if (!strcmp(tun_name, geneve_tun[i].tun_name)) {
+                return i;
+            }
+        }
+    }
+
+    shmdt(geneve_tun);
+
+    return -1;
+}
+
+static void
+set_global_geneve_tunnel_config(char *name, int num, char *localip, char *dstip, int isipv6)
+{
+    int i;
+    char ifname[CA_NLEN];
+    geneve_tun_t *geneve_tun;
+    struct in_addr local, remote;
+
+    geneve_tun = get_global_geneve_tunnel_config();
+
+    if(geneve_tun) {
+        memset(&geneve_tun[num], 0, sizeof(geneve_tun_t));
+        geneve_tun[num].valid = 1;
+        geneve_tun[num].num = num;
+        geneve_tun[num].isipv6 =  isipv6;
+        if (!isipv6) {
+            inet_aton(localip, &local);
+            inet_aton(dstip, &remote);
+            geneve_tun[num].local_ip32 = local.s_addr;
+            geneve_tun[num].remote_ip32 = remote.s_addr;
+        } else {
+            snprintf(geneve_tun[num].local_v6, sizeof(geneve_tun[num].local_v6), localip);
+            snprintf(geneve_tun[num].remote_v6, sizeof(geneve_tun[num].remote_v6), dstip);
+        }
+        strncpy(geneve_tun[num].tun_name, name, CA_NLEN);
+    }
+    shmdt(geneve_tun);
+}
+
+static void
+reset_global_geneve_tunnel_config(int num)
+{
+    geneve_tun_t *geneve_tun = get_global_geneve_tunnel_config();
+    if(geneve_tun) {
+        memset(&geneve_tun[num], 0, sizeof(geneve_tun_t));
+    }
+    shmdt(geneve_tun);
+}
+
+static int
+check_geneve_tunnel_ip_exist(char *localip, char *dstip, int isipv6)
+{
+    geneve_tun_t *geneve_tun;
+    struct in_addr local_ipv4, remote_ipv4;
+    int i;
+
+    geneve_tun = get_global_geneve_tunnel_config();
+    if(!geneve_tun) {
+        return -1;
+    }
+
+    if (!isipv6) {
+        inet_aton(localip, &local_ipv4);
+        inet_aton(dstip, &remote_ipv4);
+    }
+
+    for(i = 0; i < GENEVE_MAX_TUNNEL; i++) {
+        if (geneve_tun[i].valid && isipv6 == geneve_tun[i].isipv6) {
+            if (isipv6 && strcmp(geneve_tun[i].local_v6, localip) == 0 && strcmp(geneve_tun[i].remote_v6, dstip) == 0) {
+                return 1;
+            } else if (!isipv6 && geneve_tun[i].local_ip32 == local_ipv4.s_addr && geneve_tun[i].remote_ip32 == remote_ipv4.s_addr) {
+                return 1;
+            }
+        }
+    }
+
+    shmdt(geneve_tun);
+
+    return 0;
+}
+
+static void
+reset_geneve_config(int geneve_num) {
+    geneve_ip_t *geneve_p = get_global_geneve_config();
+    memset(&geneve_p[geneve_num], 0, sizeof(geneve_ip_t));
+    shmdt(geneve_p);
+}
+
+static void
+set_geneve_interface_mac(int geneve_num)
+{
+    char *mac = NULL;
+    int len = 0;
+    geneve_ip_t *geneve_p;
+
+    geneve_p = get_global_geneve_config();
+    if(geneve_p) {
+        get_geneve_mac(geneve_num, (void **)&mac, &len);
+        if (mac) {
+            change_kni_lladdr(geneve_p[geneve_num].kni_ifname, mac);
+            free(mac);
+        }
+        shmdt(geneve_p);
+    }
+}
+
+static void
+set_geneve_kni_interface_up(int geneve_num)
+{
+    geneve_ip_t *geneve_p;
+
+    geneve_p = get_global_geneve_config();
+    if(geneve_p) {
+        set_kni_interface_up(geneve_p[geneve_num].kni_ifname);
+        shmdt(geneve_p);
+    }
+}
+
+static int
+set_geneve_interface_mtu(int geneve_num, int mtu)
+{
+    int s;
+    char ifname[CA_NLEN];
+    geneve_ip_t *geneve_p;
+
+    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        shmdt(geneve_p);
+        printf("GENEVE: Couldn't create socket for configuring geneve %s, vni %d\n", geneve_p[geneve_num].ifname, geneve_p[geneve_num].vni);
+        return GENEVE_ERROR;
+    }
+
+    sprintf(ifname, "geneve%u", geneve_num);
+    strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
+    if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) >= 0) {
+        mtu = ifr.ifr_mtu;
+    }
+
+    geneve_p = get_global_geneve_config();
+    if(geneve_p) {
+        set_kni_interface_mtu(geneve_p[geneve_num].kni_ifname, mtu);
+    }
+}
+
+#define geneve_parent_ip_user "192.0.2.1"
+
+static void
+create_geneve_kni_interface(int geneve_num, int vni)
+{
+    char cmd[128];
+    snprintf(cmd, sizeof(cmd), "ip link add atcp_geneve%d type geneve id %d remote %s dstport %d",
+            geneve_num, vni, geneve_parent_ip_user, GENEVE_TUNNEL_DPORT);
+    system(cmd);
+}
+
+static int
+__no_geneve(int geneve_num, geneve_ip_t *geneve_p)
+{
+    int i, ret;
+    char cmd[128];
+
+    /* if from clear_vlan(), the ip address is not cleared */
+    if (geneve_p[geneve_num].ip32) {
+        if (!okay_remove_ip(geneve_p[geneve_num].ifname, 0)) {
+            return GENEVE_ERROR;
+        }
+        no_geneve_ip_address(geneve_p[geneve_num].ifname);
+    }
+
+    if (geneve_p[geneve_num].v6[0] != '\0'){
+        if (!okay_remove_ip(geneve_p[geneve_num].ifname, 1)) {
+            return GENEVE_ERROR;
+        }
+        no_geneve_ip_address(geneve_p[geneve_num].ifname);
+    }
+
+    setgeneveipinfo(geneve_num, 0, 0);
+
+#ifndef IP_MAIN
+    other_cluster_no_virtual_ifname(geneve_p[geneve_num].ifname, 0);
+#endif
+
+    set_kni_interface_down(geneve_p[geneve_num].kni_ifname);
+
+    /* Clear the geneve config */
+    ret = destroy_geneve_if(geneve_num);
+
+    /* Then, as long as that worked, clear the ip */
+    if (ret == GENEVE_SUCCESS) {
+        snprintf(cmd, sizeof(cmd), "ip link delete %s", geneve_p[geneve_num].kni_ifname);
+        system(cmd);
+    }
+
+    /* Clear everything out */
+    memset(&geneve_p[geneve_num], 0, sizeof(geneve_ip_t));
+    for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; i++) {
+        geneve_p[geneve_num].geneve_tun[i] = MAX_GENEVE_TUNNEL;
+    }
+
+    return ret;
+}
+
+int set_geneve(char *geneve_name, int vni)
+{
+    int geneve_num = 0;
+    int ret = GENEVE_SUCCESS;
+    char ifname[CA_NLEN];
+    char *mac = NULL;
+
+    /* Check the length of geneve interface name */
+    if (strlen(geneve_name) > CA_NLEN - 1) {
+        printf("Invalid GENEVE interface name. The maximum length of the GENEVE interface is %d.\n", CA_NLEN - 1);
+        return GENEVE_ERROR;
+    }
+
+    /* Check the input vni */
+    if (vni < GENEVE_VNI_MIN || vni > GENEVE_VNI_MAX) {
+        printf("Invalid VNI number. The range of the VNI number is [%d, %d].\n", GENEVE_VNI_MIN, GENEVE_VNI_MAX);
+        return GENEVE_ERROR;
+    }
+
+    /* Check the input geneve interface name is valid */
+    if (check_ifname(geneve_name)) {
+        return GENEVE_ERROR;
+    }
+
+    /* Check the input vni not be used */
+    if (geneve_vni_scan(vni)) {
+        return GENEVE_ERROR;
+    }
+
+    geneve_num = find_free_geneve();
+    if (geneve_num == -1) {
+        printf("GENEVE interfaces are used up.\n");
+        return GENEVE_ERROR;
+    }
+
+    set_global_geneve_config(geneve_name, geneve_num, vni);
+
+    /* Create geneve interface in ATCP */
+    ret = create_geneve_if(geneve_num);
+    if (ret == GENEVE_SUCCESS) {
+        sprintf(ifname, "geneve%u", geneve_num);
+        ret = set_geneve_dev_vni(ifname, vni);
+    }
+
+    if (ret == GENEVE_SUCCESS) {
+        create_geneve_kni_interface(geneve_num, vni);
+        set_geneve_interface_mac(geneve_num);
+        set_geneve_kni_interface_up(geneve_num);
+        set_geneve_interface_mtu(geneve_num, ETHER_MTU);
+    } else {
+        reset_geneve_config(geneve_num);
+    }
+
+    return ((ret == 0) ? GENEVE_SUCCESS : GENEVE_ERROR);
+}
+
+int geneve_tunnel(char *tun_name, char *localip, char *dstip) 
+{
+    int tunnel_num, isipv6, exist = 0;
+    struct in_addr local, remote;
+    struct in6_addr local6, remote6;
+
+    /* Check the length of geneve tunnel name */
+    if (strlen(tun_name) >= CA_NLEN) {
+        printf("The tunnel name should be less than %d characters.\n", MAX_TUNNEL_NAME_LEN);
+        return GENEVE_ERROR;
+    }
+
+    tunnel_num = find_free_geneve_tunnel(tun_name, &exist);
+    if (tunnel_num == -1) {
+        printf("GENEVE tunnels are used up.");
+        return GENEVE_ERROR;
+    }
+
+    /* Check tunnel not been bound */
+    if (geneve_tunnel_is_bound_kern(tun_name)) {
+        printf("The tunnel has been bound to a GENEVE interface. Remove the binding configuration for the tunnel first.\n");
+        return GENEVE_ERROR;
+    }
+
+    if (exist) {
+        printf("The tunnel has been created.\n");
+        return GENEVE_ERROR;
+    }
+
+    /* Check both local and remote ip are valid */
+    if (geneve_check_tunnel_ip(localip, dstip)) {
+        return GENEVE_ERROR;
+    }
+
+    /* Convert local ip string */
+    if((isipv6 = geneve_ip_str_convert(localip, &local, &local6)) < 0) {
+        printf("Invalid local ip address.\n");
+        return GENEVE_ERROR;
+    }
+
+    /* Convert remote ip string */
+    if(geneve_ip_str_convert(dstip, &remote, &remote6) < 0) {
+        printf("Invalid remote ip address.\n");
+        return GENEVE_ERROR;
+    }
+
+    if (check_geneve_tunnel_ip_exist(localip, dstip, isipv6)) {
+        printf("A GENEVE tunnel with the same local IP and remote IP already existed.\n");
+        return GENEVE_ERROR;
+    }
+
+    set_global_geneve_tunnel_config(tun_name, tunnel_num, localip, dstip, isipv6);
+
+    /* Create geneve tunnel in ATCP */
+    if (geneve_tunnel_kern(tun_name, localip, dstip)) {
+        reset_global_geneve_tunnel_config(tunnel_num);
+        printf("Failed to create a GENEVE tunnel.\n");
+        return GENEVE_ERROR;
+    }
+
+    return GENEVE_SUCCESS;
+}
+
+int geneve_bind(char *geneve_name, char *tun_name)
+{
+    int i, geneve_if_num, geneve_tun_num;
+    geneve_ip_t *geneve_g = NULL, *geneve_p = NULL;
+    geneve_tun_t *geneve_g_tun = NULL, *geneve_tun = NULL;
+
+    /* Check geneve interface name */
+    if (strlen(geneve_name) == 0) {
+        printf("The geneve interface name cannot be empty\n");
+        return GENEVE_ERROR;
+    }
+
+    /* Check geneve tunnel name */
+    if (strlen(tun_name) == 0) {
+        printf("The tunnel name cannot be empty\n");
+        return GENEVE_ERROR;
+    }
+
+    geneve_g = get_global_geneve_config();
+    if(!geneve_g) {
+        return GENEVE_ERROR;
+    }
+
+    /* Check and get exist geneve interface */
+    geneve_if_num = get_geneve_config_by_name(geneve_name);
+    if (geneve_if_num == -1) {
+        printf("The GENEVE interface does not exist.\n");
+        shmdt(geneve_g);
+        return GENEVE_ERROR;
+    }
+
+    geneve_p = &(geneve_g[geneve_if_num]);
+
+    geneve_g_tun = get_global_geneve_tunnel_config();
+    if(!geneve_g_tun) {
+        shmdt(geneve_g);
+        return GENEVE_ERROR;
+    }
+
+    /* Check and get exist geneve tunnel */
+    geneve_tun_num = get_geneve_tunnel_config_by_name(tun_name);
+    if (geneve_tun_num == -1) {
+        printf("No GENEVE tunnel exists.\n");
+        shmdt(geneve_g);
+        shmdt(geneve_tun);
+        return GENEVE_ERROR;
+    }
+
+    geneve_tun = &(geneve_g_tun[geneve_tun_num]);
+
+    for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; i++) {
+        if (geneve_tun_num == geneve_p->geneve_tun[i]) {
+            printf("This GENEVE has been bound to a GENEVE tunnel.\n");
+            shmdt(geneve_g);
+            shmdt(geneve_tun);
+            return GENEVE_ERROR;
+        }
+    }
+
+    for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; i++) {
+        if (geneve_p->geneve_tun[i] == MAX_GENEVE_TUNNEL) {
+            geneve_p->geneve_tun[i] = geneve_tun_num;
+            geneve_p->bound_type = GENEVE_BOUND;
+            break;
+        }
+    }
+
+    if (i == GENEVE_VNI_MAX_TUNNEL) {
+        printf("The GENEVE interface reached the binding limit (%d).\n", GENEVE_VNI_MAX_TUNNEL);
+        shmdt(geneve_g);
+        shmdt(geneve_tun);
+        return GENEVE_ERROR;
+    }
+
+    /* Bind geneve interface and tunnel in ATCP */
+    if (geneve_bind_kern(geneve_p->real_ifname, tun_name)) {
+        geneve_p->geneve_tun[i] = MAX_GENEVE_TUNNEL;
+        geneve_p->bound_type = GENEVE_UNBOUND;
+        printf("Failed to bind the GENEVE interface to a tunnel.\n");
+        shmdt(geneve_g);
+        shmdt(geneve_tun);
+        return GENEVE_ERROR;
+    }
+
+    shmdt(geneve_g);
+    shmdt(geneve_tun);
+
+    return GENEVE_SUCCESS;
+}
+
+int geneve_associate(char *geneve_name, char *vlan_name)
+{
+    int i, ret = 0;
+    int geneve_num;
+    geneve_ip_t *geneve_g = NULL, *geneve_p = NULL;
+    vlan_ip_t *vlan_p, *vlan_find = NULL;
+    static int shm_vlan_id;
+
+    geneve_g = get_global_geneve_config();
+    if(!geneve_g) {
+        return GENEVE_ERROR;
+    }
+
+    /* lookup geneve */
+    geneve_num = get_geneve_config_by_name(geneve_name);
+    if (geneve_num < 0) {
+        printf("No GENEVE interface exists.\n");
+        shmdt(geneve_g);
+        return GENEVE_ERROR;
+    }
+
+    geneve_p = &(geneve_g[geneve_num]);
+
+    if (geneve_p->geneve_gw_if[0] != '\0') {
+        if (strncmp(geneve_p->geneve_gw_if, vlan_name, CA_NLEN)) {
+            printf("Please remove the current GENEVE association first.\n");
+        }
+        shmdt(geneve_g);
+        return GENEVE_ERROR;
+    }
+
+    /*lookup vlan*/
+    shm_vlan_id = shmget(VLAN_SHM_KEY, sizeof(vlan_ip_t) * MAX_VLAN, IPC_CREAT | SHM_W | SHM_R);
+    if (shm_vlan_id < 0) {
+        printf("shmget error\n");
+        shmdt(geneve_g);
+        return GENEVE_ERROR;
+    }
+
+    vlan_p = shmat(shm_vlan_id, 0, 0);
+    if (vlan_p == (void *)(-1)) {
+        printf("shmat error\n");
+        shmdt(geneve_g);
+        return GENEVE_ERROR;
+    }
+
+    for (i = 0; i < MAX_VLAN; i++) {
+        if (strcmp(vlan_name, vlan_p[i].ifname) == 0) {
+            vlan_find = &vlan_p[i];
+            break;
+        }
+    }
+
+    if (!vlan_find) {
+        printf("No VLAN interface exists. Only VLAN interface can be associated with the GENEVE interface.\n");
+        shmdt(vlan_p);
+        shmdt(geneve_g);
+        return GENEVE_ERROR;
+    }
+
+    /* Check if already associated */
+    if (vlan_find->is_geneve_associated) {
+        printf("The VLAN interface has been associated with a GENEVE interface.\n");
+        shmdt(vlan_p);
+        shmdt(geneve_g);
+        return GENEVE_ERROR;
+    }
+
+    /* Check if vlan configured IP/IPv6 address */
+    if (vlan_find->mask32 != 0 || vlan_find->prefixlen != 0) {
+        printf("Please remove the IP address of the VLAN interface before associating it with the GENEVE interface.\n");
+        shmdt(vlan_p);
+        shmdt(geneve_g);
+        return GENEVE_ERROR;
+    }
+
+    ret = geneve_associate_kern(geneve_p->real_ifname, vlan_find->real_ifname);
+    if (ret) {
+        printf("Failed to associate GENEVE with VLAN.\n");
+        shmdt(vlan_p);
+        shmdt(geneve_g);
+        return GENEVE_ERROR;
+    }
+
+    strncpy(geneve_p->geneve_gw_if, vlan_name, CA_NLEN);
+    vlan_find->is_geneve_associated = 1;
+
+    /* Setup parent if IFF_UP flags, VLAN UP flag will be set directly in kernel
+      No need to invoke gratuitos arp since no IP address configured */
+    setvlanifflags(vlan_find->parent_ifname);
+
+    shmdt(vlan_p);
+    shmdt(geneve_g);
+
+    return GENEVE_SUCCESS;
+}
+
+int no_geneve(char *geneve_name)
+{
+    geneve_ip_t *geneve_p, geneve;
+    int i, ret, geneve_num;
+
+    if (getgeneveif(geneve_name, &geneve) != 0) {
+        printf("'%s' is not a GENEVE interface\n", geneve_name);
+        return GENEVE_ERROR;
+    }
+
+    sscanf(geneve.real_ifname, "geneve%d", &geneve_num);
+
+    if (geneve_num < 0 || geneve_num > MAX_GENEVE) {
+        printf("Improperly configured geneve for '%s'\n", geneve_name);
+        return GENEVE_ERROR;
+    }
+
+    geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+    /* must clear both ip address firstly */
+    if (geneve_p[geneve_num].ip32 || geneve_p[geneve_num].v6[0] != '\0') {
+        printf("Error: The GENEVE interface '%s' is in use.\nPlease remove ip address firstly.\n", geneve_p[geneve_num].ifname);
+        shmdt(geneve_p);
+        return GENEVE_ERROR;
+    }
+
+    for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; i++) {
+        if (geneve_p[geneve_num].geneve_tun[i] != MAX_GENEVE_TUNNEL) {
+            printf("Please remove the binding configurations of the GENEVE interface first.\n");
+            shmdt(geneve_p);
+            return GENEVE_ERROR;
+        }
+    }
+
+    if (geneve_p[geneve_num].geneve_gw_if[0] != '\0') {
+        printf("Please disassociate the VLAN interface from the GENEVE interface first.\n");
+        shmdt(geneve_p);
+        return GENEVE_ERROR;
+    }
+
+    ret = __no_geneve(geneve_num, geneve_p);
+
+    shmdt(geneve_p);
+
+    return ret;
+}
+
+int no_geneve_tunnel(char *tun_name)
+{
+    int i, ret, tun_exist, tun_num;
+    geneve_tun_t *geneve_tun;
+
+    geneve_tun = get_global_geneve_tunnel_config();
+    if (!geneve_tun) {
+        return GENEVE_ERROR;
+    }
+
+    for (i = 0; i < MAX_GENEVE_TUNNEL; i++) {
+        if (geneve_tun[i].valid && !strcmp(geneve_tun[i].tun_name, tun_name)) {
+            ret = no_geneve_tunnel_kern(tun_name);
+            break;
+        }
+    }
+
+    if (ret == -2) {
+        printf("The tunnel has been bound to a GENEVE interface.\n");
+    } else if (ret == -1) {
+        printf("GENEVE tunnel does not exist.\n");
+    } else {
+        memset(&geneve_tun[i], 0, sizeof(geneve_tun_t));
+    }
+
+    shmdt(geneve_tun);
+
+    return (ret ? GENEVE_ERROR : GENEVE_SUCCESS);
+}
+
+int no_geneve_bind(char *geneve_name, char *tun_name)
+{
+    int i, ret = 0;
+	geneve_ip_t *geneve_p, *gnv_find = NULL;
+	geneve_tun_t* gnv_tun, *gvtun_find = NULL;
+	int gnv_tun_num;
+
+	if (strlen(geneve_name) == 0) {
+		printf("The GENEVE interface name cannot be empty.\n");
+		return -1;
+	}
+
+	if (strlen(tun_name) == 0) {
+		printf("The tunnel name cannot be empty\n");
+		return -1;
+	}
+
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+	gnv_tun = get_global_geneve_tunnel_config();
+    if (!gnv_tun) {
+        return GENEVE_ERROR;
+    }
+
+	for (i = 0; i < MAX_GENEVE; ++i) {
+		if (!strcmp(geneve_name, geneve_p[i].ifname)) {
+			gnv_find = &geneve_p[i];
+			break;
+		}
+	}
+
+	for (i = 0; i < MAX_GENEVE_TUNNEL; ++i) {
+		if (!strcmp(tun_name, gnv_tun[i].tun_name)) {
+			gvtun_find = &gnv_tun[i];
+			gnv_tun_num = i;
+			break;
+		}
+	}
+
+	if (NULL == gnv_find) {
+		printf("No GENEVE interface exists.\n");
+		shmdt(geneve_p);
+		shmdt(gnv_tun);
+		return -1;
+	} else if (NULL == gvtun_find) {
+		printf("No GENEVE tunnel exists.\n");
+		shmdt(geneve_p);
+		shmdt(gnv_tun);
+		return -1;
+	}
+
+	if (gvtun_find->tun_mode == GENEVE_TUN_MCAST) {
+		if (gnv_find->bound_type != GENEVE_MCAST_TUN_BOUND) {
+			printf("The current working mode of GENEVE is p2mp. It does not match the tunnel mode.\n");
+			shmdt(geneve_p);
+			shmdt(gnv_tun);
+			return -1;
+		} else if (gnv_find->geneve_tun[0] != gnv_tun_num) {
+			printf("The GENEVE interface is not bound to a multicast tunnel.\n");
+			shmdt(geneve_p);
+			shmdt(gnv_tun);
+			return -1;
+		} else {
+			ret = no_geneve_bind_kern(gnv_find->real_ifname, tun_name);
+			if (ret == 0) {
+				gnv_find->geneve_tun[0] = MAX_GENEVE_TUNNEL;
+				gnv_find->bound_type = GENEVE_UNBOUND;
+			}
+			shmdt(geneve_p);
+			shmdt(gnv_tun);
+			return ret;
+		}
+	}
+
+	for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; ++i) {
+		if (gnv_find->geneve_tun[i] == gnv_tun_num) {
+			break;
+		}
+	}
+
+	if (i == GENEVE_VNI_MAX_TUNNEL) {
+		printf("The GENEVE interface is not bound to a p2mp tunnel.\n");
+		shmdt(geneve_p);
+		shmdt(gnv_tun);
+		return -1;
+	}
+
+	ret = no_geneve_bind_kern(gnv_find->real_ifname, tun_name);
+	if (ret != 0) {
+		shmdt(geneve_p);
+		shmdt(gnv_tun);
+		return -1;
+	}
+
+	gnv_find->geneve_tun[i] = MAX_GENEVE_TUNNEL;
+
+	gnv_find->bound_type = GENEVE_UNBOUND;
+	for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; ++i) {
+		if (gnv_find->geneve_tun[i] != MAX_GENEVE_TUNNEL) {
+			gnv_find->bound_type = GENEVE_P2P_TUN_BOUND;
+			break;
+		}
+	}
+
+	shmdt(geneve_p);
+	shmdt(gnv_tun);
+
+	return ret;
+}
+
+int no_geneve_associate(char *geneve_name)
+{
+    int i, ret=0;
+	geneve_ip_t *geneve_p, *gnv_find = NULL;
+	vlan_ip_t *vlan_p, *vlan_find = NULL;
+	static int shm_vlan_id;
+
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+	for (i = 0; i < MAX_GENEVE; ++i) {
+		if (!strncmp(geneve_name, geneve_p[i].ifname, CA_NLEN)) {
+			gnv_find = &geneve_p[i];
+			break;
+		}
+	}
+
+	if (NULL == gnv_find) {
+		printf("No GENEVE interface exists.\n");
+		shmdt(geneve_p);
+		return -1;
+	}
+
+	if (gnv_find->geneve_gw_if[0] == '\0') {
+		printf("The GENEVE interface has not been associated with a VLAN interface yet.\n");
+		shmdt(geneve_p);
+		return -1;
+	}
+
+	/*lookup vlan*/
+	shm_vlan_id = shmget(VLAN_SHM_KEY, sizeof(vlan_ip_t) * MAX_VLAN,
+	IPC_CREAT | SHM_W | SHM_R);
+
+	if (shm_vlan_id < 0) {
+		perror("shmget error\n");
+		shmdt(geneve_p);
+		return -1;
+	}
+
+	vlan_p = shmat(shm_vlan_id, 0, 0);
+	if (vlan_p == (void *)(-1)) {
+		perror("shmat error\n");
+		shmdt(geneve_p);
+		return -1;
+	}
+
+	for (i = 0; i < MAX_VLAN; ++i) {
+		if (strcmp(gnv_find->geneve_gw_if, vlan_p[i].ifname) == 0) {
+			vlan_find = &vlan_p[i];
+			break;
+		}
+	}
+
+	if (NULL == vlan_find) {
+		printf("No VLAN interface exists. Only the VLAN interface can be associated with the GENEVE interface.\n");
+		shmdt(geneve_p);
+		shmdt(vlan_p);
+		return -1;
+	}
+
+	if (vlan_find->is_geneve_associated == 0) {
+		printf("Failed to associate GENEVE with VLAN.");
+	}
+
+	ret = no_geneve_associate_kern(gnv_find->real_ifname, vlan_find->real_ifname);
+	if (ret) {
+		printf("Failed to disassociate GENEVE from VLAN.\n");
+		shmdt(geneve_p);
+		shmdt(vlan_p);
+		return -1;
+	}
+
+	vlan_find->is_geneve_associated = 0;
+	memset(gnv_find->geneve_gw_if, 0, CA_NLEN);
+
+	shmdt(geneve_p);
+	shmdt(vlan_p);
+	return 0;
+}
+
+int show_geneve_interface(void)
+{
+    geneve_ip_t *geneve_p;
+    int i;
+
+    geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+    for (i = 0; i < MAX_GENEVE; ++i) {
+        if (geneve_p[i].vni == 0) {
+            continue;
+        }
+        printf("geneve interface \"%s\" %d\n", geneve_p[i].ifname, geneve_p[i].vni);
+    }
+
+    shmdt(geneve_p);
+
+    return GENEVE_SUCCESS;
+}
+
+int show_geneve_port(void)
+{
+    size_t len;
+    int geneve_port;
+
+    len = sizeof(geneve_port);
+    sysctlbyname("net.inet.clicktcp.geneve_port", &geneve_port, &len, NULL, 0);
+    printf("geneve port %d \n", geneve_port);
+
+    return 0;
+}
+
+int show_geneve_learn(void)
+{
+    size_t len;
+    int geneve_learn;
+
+    len = sizeof(geneve_learn);
+    sysctlbyname("net.inet.clicktcp.geneve_learn", &geneve_learn, &len, NULL, 0);
+
+    if (geneve_learn == GENEVE_LEARN_ON) {
+        printf("geneve learn on\n");
+    } else if (geneve_learn == GENEVE_LEARN_OFF) {
+        printf("geneve learn off\n");
+    }
+
+    return 0;
+}
+
+int show_geneve_bind(char *geneve_name) //here
+{
+    int i, j, ret = 0;
+	geneve_ip_t *geneve_p;
+	geneve_tun_t* gnv_tun;
+	int gnv_tun_num;
+
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+	gnv_tun = get_global_geneve_tunnel_config();
+    if (!gnv_tun) {
+        return GENEVE_ERROR;
+    }
+
+	if (NULL == geneve_name || geneve_name[0] == '\0') {
+		for (i = 0; i < MAX_GENEVE; ++i) {
+			if (geneve_p[i].vni == 0) {
+				continue;
+			}
+			for (j = 0; j < GENEVE_VNI_MAX_TUNNEL; ++j) {
+				if (geneve_p[i].geneve_tun[j] != MAX_GENEVE_TUNNEL) {
+					gnv_tun_num = geneve_p[i].geneve_tun[j];
+					printf("geneve bind %s %s\n", geneve_p[i].ifname, gnv_tun[gnv_tun_num].tun_name);
+				}
+			}
+		}
+	} else {
+		for (i = 0; i < MAX_GENEVE; ++i) {
+			if (strncmp(geneve_p[i].ifname, geneve_name, CA_NLEN)) {
+				continue;
+			}
+			for (j = 0; j < GENEVE_VNI_MAX_TUNNEL; ++j) {
+				if (geneve_p[i].geneve_tun[j] != MAX_GENEVE_TUNNEL) {
+					gnv_tun_num = geneve_p[i].geneve_tun[j];
+					printf("geneve bind %s %s\n", geneve_p[i].ifname, gnv_tun[gnv_tun_num].tun_name);
+				}
+			}
+			break;
+		}
+		if (i == MAX_GENEVE)
+			printf("GENEVE interface does not exist.\n");
+	}
+
+	shmdt(geneve_p);
+	shmdt(gnv_tun);
+	return 0;
+}
+
+int clear_geneve_forwarding()
+{
+	geneve_ip_t* geneve_p;
+	int i, ret = 0;
+
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+	for (i = 0; i < MAX_GENEVE; ++i) {
+		if (geneve_p[i].vni ==0) {
+			continue;
+		}
+		ret = clear_geneve_forwarding_kern(geneve_p[i].vni);
+	}
+
+	if (ret) {
+		perror("GENEVE: clear forwarding table failed");
+	}
+
+	shmdt(geneve_p);
+	return 0;
+}
+
+int show_geneve_associate(char *geneve_name)
+{
+    int i;
+	geneve_ip_t *geneve_p;
+
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+	if (NULL == geneve_name || geneve_name[0] == '\0') {
+		for (i = 0; i < MAX_GENEVE; ++i) {
+			if (geneve_p[i].vni == 0) {
+				continue;
+			}
+			if (geneve_p[i].geneve_gw_if[0] != '\0') {
+				printf("geneve associate %s %s\n", geneve_p[i].ifname, geneve_p[i].geneve_gw_if);
+			}
+		}
+	} else {
+		for (i = 0; i < MAX_GENEVE; ++i) {
+			if (strncmp(geneve_p[i].ifname, geneve_name, CA_NLEN)) {
+				continue;
+			}
+			if (geneve_p[i].geneve_gw_if[0] != '\0') {
+				printf("geneve associate %s %s\n", geneve_p[i].ifname, geneve_p[i].geneve_gw_if);
+			}
+			break;
+		}
+		if (i == MAX_GENEVE)
+			printf("The GENEVE interface does not exist.\n");
+	}
+
+	shmdt(geneve_p);
+	return 0;
+}
+
+int show_geneve_tunnel(char *tun_name)
+{
+    int i, ret, found = 0;
+    struct in_addr addr;
+    char src[32], dst[32];
+    geneve_tun_t *geneve_tun = NULL, geneve_tun_tmp;
+
+    geneve_tun = get_global_geneve_tunnel_config();
+    if (!geneve_tun) {
+        return GENEVE_ERROR;
+    }
+
+    for (i = 0; i < MAX_GENEVE_TUNNEL; i++) {
+        geneve_tun_tmp = geneve_tun[i];
+
+        if (strlen(tun_name) > 0 && strcmp(geneve_tun_tmp.tun_name, tun_name)) {
+            continue;
+        }
+
+        if (!geneve_tun_tmp.valid) {
+            continue;
+        }
+
+        found = 1;
+
+        if (geneve_tun_tmp.isipv6) {
+            printf("geneve tunnel %s %s %s\n", geneve_tun_tmp.tun_name, geneve_tun_tmp.local_v6, geneve_tun_tmp.remote_v6);
+        } else {
+            addr.s_addr = geneve_tun_tmp.local_ip32;
+            strcpy(src, inet_ntoa(addr));
+            addr.s_addr = geneve_tun_tmp.remote_ip32;
+            strcpy(dst, inet_ntoa(addr));
+            printf("geneve tunnel %s %s %s\n", geneve_tun_tmp.tun_name, src, dst);
+        }
+    }
+
+    if (!found) {
+        printf("No such vxlan tunnel configured.\n");
+    }
+
+    shmdt(geneve_tun);
+
+    return 0;
+}
+
+int show_geneve_forwarding(int vni, char *mac)
+{
+    int i, ret;
+	geneve_ip_t *geneve_p;
+
+	if (vni < MIN_GENEVE_VNI || vni > MAX_GENEVE_VNI) {
+		printf("GENEVE: vni %d is invalid, it should be in range[%d, %d].", vni, MIN_GENEVE_VNI, MAX_GENEVE_VNI);
+		return GENEVE_ERROR;
+	}
+
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+	
+	for (i = 0; i < MAX_GENEVE; ++i) {
+		if (geneve_p[i].vni == vni) {
+			ret = show_geneve_forwarding_kern(vni, mac, geneve_p[i].geneve_gw_if); //here
+			shmdt(geneve_p);
+			return ret;
+		}
+	}
+
+	printf("GENEVE does not exist.\n");
+	shmdt(geneve_p);
+	return GENEVE_ERROR;
+}
+
+int show_geneve_all(void)
+{
+    char *geneve_config;
+
+	geneve_config = write_geneve();
+	if (geneve_config) {
+		printf("%s", geneve_config);
+		free(geneve_config);
+	}
+
+	return 0;
+}
+
+int clear_geneve_bind(char *geneve_name)
+{
+    int i, j, ret = 0;
+	geneve_ip_t *geneve_p;
+	geneve_tun_t *gnv_tun;
+	int gnv_tun_num;
+
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+	gnv_tun = get_global_geneve_tunnel_config();
+    if (!gnv_tun) {
+        return GENEVE_ERROR;
+    }
+
+	if (NULL== geneve_name || geneve_name[0]=='\0') {
+		for (i = 0; i < MAX_GENEVE; ++i) {
+			if (geneve_p[i].vni == 0) {
+				continue;
+			}
+			for (j = 0; j < GENEVE_VNI_MAX_TUNNEL; ++j) {
+				if (geneve_p[i].geneve_tun[j] != MAX_GENEVE_TUNNEL) {
+					gnv_tun_num = geneve_p[i].geneve_tun[j];
+					/*printf("clearing bind %s %s\n", geneve_p[i].real_ifname, gnv_tun[gnv_tun_num].tun_name);*/
+					ret = no_geneve_bind_kern(geneve_p[i].real_ifname, gnv_tun[gnv_tun_num].tun_name);
+					if (ret) {
+						printf("Failed to clear GENEVE binding configurations.\n");
+						return ret;
+					}
+					geneve_p[i].geneve_tun[j] = MAX_GENEVE_TUNNEL;
+				}
+			}
+			geneve_p[i].bound_type = GENEVE_UNBOUND;
+		}
+	} else {
+		for (i = 0; i < MAX_GENEVE; ++i) {
+			if (strncmp(geneve_p[i].ifname, geneve_name, CA_NLEN)) {
+				continue;
+			}
+			for (j = 0; j < GENEVE_VNI_MAX_TUNNEL; ++j) {
+				if (geneve_p[i].geneve_tun[j] != MAX_GENEVE_TUNNEL) {
+					gnv_tun_num = geneve_p[i].geneve_tun[j];
+					/*printf("clearing bind %s %s\n", geneve_p[i].real_ifname, gnv_tun[gnv_tun_num].tun_name);*/
+					ret = no_geneve_bind_kern(geneve_p[i].real_ifname, gnv_tun[gnv_tun_num].tun_name);
+					if (ret) {
+						printf("Failed to clear GENEVE binding configurations.\n");
+						return ret;
+					}
+					geneve_p[i].geneve_tun[j] = MAX_GENEVE_TUNNEL;
+				}
+			}
+			geneve_p[i].bound_type = GENEVE_UNBOUND;
+			break;
+		}
+		if (i == MAX_GENEVE)
+			printf("GENEVE interface does not exist.\n");
+	}
+
+	shmdt(geneve_p);
+	shmdt(gnv_tun);
+	return 0;
+}
+
+int clear_geneve_associate(void) 
+{
+    int i, j, ret = 0;
+	geneve_ip_t *geneve_p;
+	vlan_ip_t *vlan_p, *vlan_find = NULL;
+	static int shm_vlan_id;
+
+	geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+	/*lookup vlan*/
+	shm_vlan_id = shmget(VLAN_SHM_KEY, sizeof(vlan_ip_t) * MAX_VLAN, IPC_CREAT | SHM_W | SHM_R);
+	if (shm_vlan_id < 0) {
+		shmdt(geneve_p);
+		perror("shmget error\n");
+		return -1;
+	}
+
+	vlan_p = shmat(shm_vlan_id, 0, 0);
+	if (vlan_p == (void *)(-1)) {
+		perror("shmat error\n");
+		shmdt(geneve_p);
+		return -1;
+	}
+
+	for (i = 0; i < MAX_GENEVE; ++i) {
+		if (geneve_p[i].geneve_gw_if[0] != '\0') {
+			for (j = 0; j < MAX_VLAN; ++j) {
+				if (strcmp(geneve_p[i].geneve_gw_if, vlan_p[j].ifname) == 0) {
+					vlan_find = &vlan_p[j];
+					if (vlan_find->is_geneve_associated == 0) {
+						printf("Failed to associate GENEVE with VLAN.\n");
+					}
+					break;
+				}
+			}
+			ret = no_geneve_associate_kern(geneve_p[i].real_ifname, vlan_find->real_ifname);
+			if (ret) {
+				perror("Failed to clear the Layer2 associations.\n");
+				shmdt(geneve_p);
+				shmdt(vlan_p);
+				return -1;
+			}
+			vlan_find->is_geneve_associated = 0;
+			memset(geneve_p[i].geneve_gw_if, 0, CA_NLEN);
+		}
+	}
+
+	shmdt(geneve_p);
+	shmdt(vlan_p);
+	return 0;
+}
+
+int clear_geneve_tunnel(void)
+{
+    int i, ret;
+    geneve_tun_t *geneve_tun;
+
+    geneve_tun = get_global_geneve_tunnel_config();
+    if (!geneve_tun) {
+        return GENEVE_ERROR;
+    }
+
+    for (i = 0; i < MAX_GENEVE_TUNNEL; i++) {
+        if (geneve_tun[i].valid == 0) {
+            continue;
+        }
+
+        ret = no_geneve_tunnel_kern(geneve_tun[i].tun_name);
+        if (ret) {
+            printf("Failed to clear GENEVE tunnels.\n");
+            shmdt(geneve_tun);
+            return ret;
+        }
+        memset(&geneve_tun[i], 0, sizeof(geneve_tun_t));
+    }
+
+    shmdt(geneve_tun);
+
+    return 0;
+}
+
+int clear_geneve_interface(void)
+{
+    geneve_ip_t *geneve_p;
+    int i, j;
+
+    geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return GENEVE_ERROR;
+    }
+
+    for (i = 0; i < MAX_GENEVE; i++) {
+        if (geneve_p[i].vni) {
+            if (geneve_p[i].geneve_gw_if[0]!='\0') {
+                shmdt(geneve_p);
+                printf("Please remove geneve associate first.\n");
+                return GENEVE_ERROR;
+            }
+            for (j = 0; j < GENEVE_VNI_MAX_TUNNEL; j++) {
+                if (geneve_p[i].geneve_tun[j] != MAX_GENEVE_TUNNEL) {
+                    shmdt(geneve_p);
+                    printf("Please remove the geneve-tunnel bind first.\n");
+                    return GENEVE_ERROR;
+                }
+            }
+            __no_geneve(i, geneve_p);
+        }
+    }
+
+    shmdt(geneve_p);
+
+    return GENEVE_SUCCESS;
+}
+
+int clear_geneve_all(void)
+{
+    clear_geneve_forwarding();
+    clear_geneve_bind(NULL);
+    clear_geneve_associate();
+    clear_geneve_tunnel();
+    clear_geneve_interface();
+    clear_geneve_environ_kern();
+    return GENEVE_SUCCESS;
+}
+
+char *write_geneve(void)
+{
+    char *ret, *cur;
+    char ipbuf[32], nmbuf[32], tun_src[32], tun_dst[32];
+    struct in_addr addr;
+    int i, j;
+    int enable = 0, port = 0, learn = 0, num = 0;
+    size_t len = sizeof(int);
+    geneve_ip_t *geneve_p;
+    geneve_tun_t *geneve_tun;
+
+    /* Allocate enough room for everything to be used */
+    ret = (char *)malloc((sizeof(geneve_ip_t)*2) * MAX_GENEVE);
+    if (ret == NULL) {
+        printf("Insufficent memory\n");
+        return NULL;
+    }
+
+    cur = ret;
+    *cur = 0;
+
+    geneve_p = get_global_geneve_config();
+    if(!geneve_p) {
+        return NULL;
+    }
+
+    geneve_tun = get_global_geneve_tunnel_config();
+    if (!geneve_tun) {
+        return NULL;
+    }
+
+    sysctlbyname("net.inet.clicktcp.geneve_enable", &enable, &len, NULL, 0);
+    sysctlbyname("net.inet.clicktcp.geneve_port", &port, &len, NULL, 0);
+    sysctlbyname("net.inet.clicktcp.geneve_learn", &learn, &len, NULL, 0);
+
+    cur += sprintf(cur, "geneve %s\n", enable ? "enable" : "disable");
+    cur += sprintf(cur, "geneve port %d\n", port);
+    cur += sprintf(cur, "geneve learn %s\n", (learn == GENEVE_LEARN_ON) ? "on" : "off");
+
+    for (i = 0; i < MAX_GENEVE_TUNNEL; i++) {
+        if (geneve_tun[i].valid == 0) {
+            continue;
+        }
+        if (!geneve_tun[i].isipv6) {
+            addr.s_addr = geneve_tun[i].local_ip32;
+            strcpy(tun_src, inet_ntoa(addr));
+            addr.s_addr = geneve_tun[i].remote_ip32;
+            strcpy(tun_dst, inet_ntoa(addr));
+            cur += sprintf(cur, "geneve tunnel \"%s\" %s %s\n", geneve_tun[i].tun_name, tun_src, tun_dst);
+        } else {
+            cur += sprintf(cur, "geneve tunnel \"%s\" %s %s\n", geneve_tun[i].tun_name, geneve_tun[i].local_v6, geneve_tun[i].remote_v6);
+        }
+    }
+
+    for (i = 0; i < MAX_GENEVE; i++) {
+        if (geneve_p[i].vni == 0) {
+            continue;
+        }
+
+        cur += sprintf(cur, "geneve interface \"%s\" %d\n", geneve_p[i].ifname, geneve_p[i].vni);
+
+        for (j = 0; j < GENEVE_VNI_MAX_TUNNEL; j++) {
+            if (geneve_p[i].geneve_tun[j] != MAX_GENEVE_TUNNEL) {
+                num = geneve_p[i].geneve_tun[j];
+                cur += sprintf(cur, "geneve bind \"%s\" \"%s\"\n", geneve_p[i].ifname, geneve_tun[num].tun_name);
+            }
+        }
+
+        if (geneve_p[i].ip32) {
+            addr.s_addr = geneve_p[i].ip32;
+            strcpy(ipbuf, inet_ntoa(addr));
+            addr.s_addr = geneve_p[i].mask32;
+            strcpy(nmbuf, inet_ntoa(addr));
+            cur += sprintf(cur, "ip address \"%s\" %s %s\n", geneve_p[i].ifname, ipbuf, nmbuf);
+        }
+
+        if (geneve_p[i].v6[0]){
+            cur += sprintf(cur, "ip address \"%s\" %s %d\n", geneve_p[i].ifname, geneve_p[i].v6, geneve_p[i].prefixlen);
+        }
+
+        if (geneve_p[i].geneve_gw_if[0] != '\0') {
+            cur += sprintf(cur, "geneve associate %s %s\n", geneve_p[i].ifname, geneve_p[i].geneve_gw_if);
+        }
+    }
+
+	shmdt(geneve_p);
+	shmdt(geneve_tun);
+
+	return ret;
+}
+
+/* GENEVE end */
\ No newline at end of file
Index: /branches/rel_apv_10_7/usr/click/lib/libkernelapi/addCommands.pm
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libkernelapi/addCommands.pm	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libkernelapi/addCommands.pm	(working copy)
@@ -5589,15 +5589,120 @@
 							{type=> "U32"},
 							{type=> "U32"},
 							],
-    	},
-    	{
-		cmd_attribute => "CMD_KERN_API",
-        	function_name => "get_vxlan_mac",
-        	function_args => [
-        					{type=> "U32"},
-        					{type=> "OUTDATA"},
-							],
-    	},
+        },
+        {
+            cmd_attribute => "CMD_KERN_API",
+            function_name => "get_geneve_mac",
+            function_args => [
+                                {type=> "U32"},
+                                {type=> "OUTDATA"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API|CMD_KAPI_LOCK",
+            function_name => "create_geneve_if",
+            function_args => [
+                                {type=> "U32"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API|CMD_KAPI_LOCK",
+            function_name => "destroy_geneve_if",
+            function_args => [
+                                {type=> "U32"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API",
+            function_name => "geneve_tunnel_kern",
+            function_args => [
+                                {type=> "STRING"},
+                                {type=> "IPADDR"},
+                                {type=> "IPADDR"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API",
+            function_name => "no_geneve_tunnel_kern",
+            function_args => [
+                                {type=> "STRING"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API",
+            function_name => "geneve_tunnel_is_bound_kern",
+            function_args => [
+                                {type=> "STRING"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API",
+            function_name => "geneve_bind_kern",
+            function_args => [
+                                {type=> "STRING"},
+                                {type=> "STRING"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API",
+            function_name => "no_geneve_bind_kern",
+            function_args => [
+                                {type=> "STRING"},
+                                {type=> "STRING"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API",
+            function_name => "geneve_associate_kern",
+            function_args => [
+                                {type=> "STRING"},
+                                {type=> "STRING"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API",
+            function_name => "no_geneve_associate_kern",
+            function_args => [
+                            {type=> "STRING"},
+                            {type=> "STRING"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API",
+            function_name => "clear_geneve_environ_kern",
+            function_args => [],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API",
+            function_name => "show_geneve_forwarding_kern",
+            function_args => [
+                            {type=> "U32"},
+                            {type=> "STRING"},
+                            {type=> "STRING"},
+                            ],
+        },
+        {
+            cmd_attribute => "CMD_KERN_API|CMD_KAPI_LOCK",
+            function_name => "clear_geneve_forwarding_kern",
+            function_args => [
+                            {type=> "U32"},
+                            ],
+        },
+            {
+            cmd_attribute => "CMD_KERN_API|CMD_KAPI_NOLOCK",
+            function_name => "write_geneve_forwarding_kern",
+            function_args => [
+                            {type => "OUTDATA"},
+                            ],
+        },
+        {
+        cmd_attribute => "CMD_KERN_API",
+            function_name => "get_vxlan_mac",
+            function_args => [
+                            {type=> "U32"},
+                            {type=> "OUTDATA"},
+                            ],
+        },
     	{
 		cmd_attribute => "CMD_KERN_API|CMD_KAPI_LOCK",
         	function_name => "create_vxlan_if",
@@ -5709,20 +5814,20 @@
         function_args => [
                 {type => "OUTDATA"},
             ],
-   	 },
-	{
-		cmd_attribute => "CMD_KERN_API",
-        	function_name => "slb_real_hc_kern",
-        	function_args => [
-                	{type => "STRING"},
-                	{type => "STRING"},
-                	{type => "STRING"},
-                	{type => "U16"},
-                	{type => "STRING"},
-                	{type => "U32"},
-                	{type => "U32"},
-        	],
-    	},
+        },
+    {
+        cmd_attribute => "CMD_KERN_API",
+            function_name => "slb_real_hc_kern",
+            function_args => [
+                    {type => "STRING"},
+                    {type => "STRING"},
+                    {type => "STRING"},
+                    {type => "U16"},
+                    {type => "STRING"},
+                    {type => "U32"},
+                    {type => "U32"},
+            ],
+        },
      	{
 		cmd_attribute => "CMD_KERN_API|CMD_KAPI_LOCK_UPROXY",
         	function_name => "slb_real_diameter_kern",
Index: /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm	(working copy)
@@ -8264,7 +8264,7 @@
 		function_name => "ip_address_wrapper",
 		function_args => [ {
 									type => "STRING",
-									help_string => "Interface name (<system_ifname>|<mnet_ifname>|<vlan_ifname>|<bond_ifname>|<vxlan_ifname>)",
+									help_string => "Interface name (<system_ifname>|<mnet_ifname>|<vlan_ifname>|<bond_ifname>|<vxlan_ifname>|<geneve_ifname>)",
 									optional => "NO",
 								},
 								{
@@ -8314,7 +8314,7 @@
 		function_name => "no_ip_address_wrapper",
 		function_args => [ {
 									type => "STRING",
-									help_string => "Interface name (<system_ifname>|<mnet_ifname>|<vlan_ifname>|<bond_ifname>|<vxlan_ifname>)",
+									help_string => "Interface name (<system_ifname>|<mnet_ifname>|<vlan_ifname>|<bond_ifname>|<vxlan_ifname>|<geneve_ifname>)",
 									optional => "NO",
 				   },
 					{
@@ -43461,17 +43461,18 @@
 		user_level => "CLI_LEVEL_CONFIG",
 		help_string => "Create a GENEVE interface",
 		function_name => "set_geneve",
-		function_args => [ {
-		                     type => "STRING",
-				     help_string => "GENEVE interface name",
-				     optional => "NO",
-				 },
-				 {
-		                     type => "U32",
-				     help_string => "VNI number",
-				     optional => "NO",
-				 },
-			 ],
+		function_args => [
+							{
+								type => "STRING",
+								help_string => "GENEVE interface name",
+								optional => "NO",
+							},
+							{
+								type => "U32",
+								help_string => "VNI number",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43481,13 +43482,15 @@
 		user_level => "CLI_LEVEL_CONFIG",
 		help_string => "Configure GENEVE port",
 		function_name => "geneve_port_func",
-		function_args => [ {
-		                     type => "U16",
-				     help_string => "GENEVE port number (1025-65000, default = 6081)",
-				     optional => "NO",
-				     min => "1025",
-				     max => "65000",
-				 }, ],
+		function_args => [
+							{
+								type => "U16",
+								help_string => "GENEVE port number (1025-65000, default = 6081)",
+								optional => "NO",
+								min => "1025",
+								max => "65000",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43517,11 +43520,13 @@
 		user_level => "CLI_LEVEL_CONFIG",
 		help_string => "Enable or disable GENEVE learning function",
 		function_name => "geneve_learn_func",
-		function_args => [{
-							type => "STRING",
-							help_string => "on or off",
-							optional => "NO",
-						},],
+		function_args => [
+							{
+								type => "STRING",
+								help_string => "on or off",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43532,22 +43537,22 @@
 		help_string => "Create a GENEVE tunnel",
 		function_name => "geneve_tunnel",
 		function_args => [
-						{
-							type => "STRING",
-							help_string => "Tunnel name",
-							optional => "NO",
-						},
-						{
-							type => "IPADDR",
-							help_string => "Local GTEP IP",
-							optional => "NO",
-						},
-						{
-							type => "IPADDR",
-							help_string => "Remote GTEP IP",
-							optional => "NO",
-						},
-					  ],
+							{
+								type => "STRING",
+								help_string => "Tunnel name",
+								optional => "NO",
+							},
+							{
+								type => "IPADDR",
+								help_string => "Local GTEP IP",
+								optional => "NO",
+							},
+							{
+								type => "IPADDR",
+								help_string => "Remote GTEP IP",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43558,17 +43563,17 @@
 		help_string => "Bind a GENEVE interface to a GENEVE tunnel",
 		function_name => "geneve_bind",
 		function_args => [
-						{
-							type => "STRING",
-							help_string => "GENEVE interface name",
-							optional => "NO",
-						},
-						{
-							type => "STRING",
-							help_string => "Tunnel name",
-							optional => "NO",
-						},
-					  ],
+							{
+								type => "STRING",
+								help_string => "GENEVE interface name",
+								optional => "NO",
+							},
+							{
+								type => "STRING",
+								help_string => "Tunnel name",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43579,17 +43584,17 @@
 		help_string => "Associate GENEVE with VLAN to enable GENEVE gateway function",
 		function_name => "geneve_associate",
 		function_args => [
-						{
-							type => "STRING",
-							help_string => "GENEVE interface name",
-							optional => "NO",
-						},
-						{
-							type => "STRING",
-							help_string => "VLAN interface name",
-							optional => "NO",
-						},
-					  ],
+							{
+								type => "STRING",
+								help_string => "GENEVE interface name",
+								optional => "NO",
+							},
+							{
+								type => "STRING",
+								help_string => "VLAN interface name",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "MENU",
@@ -43609,22 +43614,22 @@
 		help_string => "Add a static GENEVE forwarding entry to remote GTEP",
 		function_name => "geneve_forwarding_remote_add",
 		function_args => [
-						{
-							type => "U32",
-							help_string => "VNI number",
-							optional => "NO",
-						},
-						{
-							type => "STRING",
-							help_string => "Destination MAC address (x:x:x:x:x:x)",
-							optional => "NO",
-						},
-						{
-							type => "IPADDR",
-							help_string => "Remote GTEP IP address",
-							optional => "NO",
-						},
-					  ],
+							{
+								type => "U32",
+								help_string => "VNI number",
+								optional => "NO",
+							},
+							{
+								type => "STRING",
+								help_string => "Destination MAC address (x:x:x:x:x:x)",
+								optional => "NO",
+							},
+							{
+								type => "IPADDR",
+								help_string => "Remote GTEP IP address",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43635,17 +43640,17 @@
 		help_string => "Add a static GENEVE forwarding entry to L2 interface",
 		function_name => "geneve_forwarding_local_add",
 		function_args => [
-						{
-							type => "U32",
-							help_string => "VNI number",
-							optional => "NO",
-						},
-						{
-							type => "STRING",
-							help_string => "Destination MAC address (x:x:x:x:x:x)",
-							optional => "NO",
-						},
-					  ],
+							{
+								type => "U32",
+								help_string => "VNI number",
+								optional => "NO",
+							},
+							{
+								type => "STRING",
+								help_string => "Destination MAC address (x:x:x:x:x:x)",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "MENU",
@@ -43664,12 +43669,13 @@
 		user_level => "CLI_LEVEL_CONFIG",
 		help_string => "Delete a GENEVE interface",
 		function_name => "no_geneve",
-		function_args => [ {
-		                     type => "STRING",
-				     help_string => "GENEVE interface name",
-				     optional => "NO",
-				 },
-			 ],
+		function_args => [
+							{
+								type => "STRING",
+								help_string => "GENEVE interface name",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43680,12 +43686,12 @@
 		help_string => "Delete a GENEVE tunnel",
 		function_name => "no_geneve_tunnel",
 		function_args => [
-						{
-							type => "STRING",
-							help_string => "Tunnel name",
-							optional => "NO",
-						},
-					  ],
+							{
+								type => "STRING",
+								help_string => "Tunnel name",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43696,17 +43702,17 @@
 		help_string => "Unbind GENEVE interface from GENEVE tunnel",
 		function_name => "no_geneve_bind",
 		function_args => [
-						{
-							type => "STRING",
-							help_string => "GENEVE interface name",
-							optional => "NO",
-						},
-						{
-							type => "STRING",
-							help_string => "Tunnel name",
-							optional => "NO",
-						},
-					  ],
+							{
+								type => "STRING",
+								help_string => "GENEVE interface name",
+								optional => "NO",
+							},
+							{
+								type => "STRING",
+								help_string => "Tunnel name",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43717,17 +43723,17 @@
 		help_string => "Disassociate GENEVE from VLAN",
 		function_name => "no_geneve_associate",
 		function_args => [
-						{
-							type => "STRING",
-							help_string => "GENEVE interface name",
-							optional => "NO",
-						},
-						{
-							type => "STRING",
-							help_string => "VLAN interface name",
-							optional => "NO",
-						},
-					  ],
+							{
+								type => "STRING",
+								help_string => "GENEVE interface name",
+								optional => "NO",
+							},
+							{
+								type => "STRING",
+								help_string => "VLAN interface name",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "MENU",
@@ -43747,17 +43753,17 @@
 		help_string => "Delete a static GENEVE forwarding entry to remote GTEP",
 		function_name => "geneve_forwarding_remote_del",
 		function_args => [
-						{
-							type => "U32",
-							help_string => "VNI number",
-							optional => "NO",
-						},
-						{
-							type => "STRING",
-							help_string => "Destination MAC address (x:x:x:x:x:x)",
-							optional => "NO",
-						},
-					  ],
+							{
+								type => "U32",
+								help_string => "VNI number",
+								optional => "NO",
+							},
+							{
+								type => "STRING",
+								help_string => "Destination MAC address (x:x:x:x:x:x)",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43768,17 +43774,17 @@
 		help_string => "Delete a static GENEVE forwarding entry to L2 interface",
 		function_name => "geneve_forwarding_local_del",
 		function_args => [
-						{
-							type => "U32",
-							help_string => "VNI number",
-							optional => "NO",
-						},
-						{
-							type => "STRING",
-							help_string => "Destination MAC address (x:x:x:x:x:x)",
-							optional => "NO",
-						},
-					  ],
+							{
+								type => "U32",
+								help_string => "VNI number",
+								optional => "NO",
+							},
+							{
+								type => "STRING",
+								help_string => "Destination MAC address (x:x:x:x:x:x)",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "MENU",
@@ -43827,13 +43833,14 @@
 		user_level => "CLI_LEVEL_ENABLE",
 		help_string => "Display tunnel binding configurations",
 		function_name => "show_geneve_bind",
-		function_args => [ {
-		                     type => "STRING",
-				     help_string => "GENEVE interface name",
-				     optional => "YES",
-				     default_value => "\"\"",
-				 },
-			 ],
+		function_args => [
+							{
+								type => "STRING",
+								help_string => "GENEVE interface name",
+								optional => "YES",
+								default_value => "\"\"",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43843,13 +43850,14 @@
 		user_level => "CLI_LEVEL_ENABLE",
 		help_string => "Display associated Layer 2 configurations",
 		function_name => "show_geneve_associate",
-		function_args => [ {
-		                     type => "STRING",
-				     help_string => "GENEVE interface name",
-				     optional => "YES",
-				     default_value => "\"\"",
-				 },
-			 ],
+		function_args => [
+							{
+								type => "STRING",
+								help_string => "GENEVE interface name",
+								optional => "YES",
+								default_value => "\"\"",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43859,13 +43867,14 @@
 		user_level => "CLI_LEVEL_ENABLE",
 		help_string => "Display GENEVE tunnel configurations",
 		function_name => "show_geneve_tunnel",
-		function_args => [ {
-		                     type => "STRING",
-				     help_string => "GENEVE tunnel name",
-				     optional => "YES",
-				     default_value => "\"\"",
-				 },
-			 ],
+		function_args => [
+							{
+								type => "STRING",
+								help_string => "GENEVE tunnel name",
+								optional => "YES",
+								default_value => "\"\"",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43875,18 +43884,19 @@
 		user_level => "CLI_LEVEL_ENABLE",
 		help_string => "Display all GENEVE forwarding entries",
 		function_name => "show_geneve_forwarding",
-		function_args => [ {
-		                     type => "U32",
-				     help_string => "VNI number",
-				     optional => "NO",
-				 },
-				 {
-		                     type => "STRING",
-				     help_string => "MAC address",
-				     optional => "YES",
-				     default_value => "\"\"",
-				 },
-			 ],
+		function_args => [
+							{
+								type => "U32",
+								help_string => "VNI number",
+								optional => "NO",
+							},
+							{
+								type => "STRING",
+								help_string => "MAC address",
+								optional => "YES",
+								default_value => "\"\"",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43915,13 +43925,14 @@
 		user_level => "CLI_LEVEL_CONFIG",
 		help_string => "Clear tunnel binding configurations of GENEVE interfaces",
 		function_name => "clear_geneve_bind",
-		function_args => [ {
-		                     type => "STRING",
-				     help_string => "GENEVE interface name",
-				     optional => "YES",
-				     default_value => "\"\"",
-				 },
-			 ],
+		function_args => [
+							{
+								type => "STRING",
+								help_string => "GENEVE interface name",
+								optional => "YES",
+								default_value => "\"\"",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43980,12 +43991,13 @@
 		user_level => "CLI_LEVEL_CONFIG",
 		help_string => "Clear all static GENEVE forwarding entries",
 		function_name => "clear_geneve_forwarding_static",
-		function_args => [ {
-		                     type => "U32",
-				     help_string => "VNI number",
-				     optional => "NO",
-				 },
-			 ],
+		function_args => [
+							{
+								type => "U32",
+								help_string => "VNI number",
+								optional => "NO",
+							}
+						]
 	},
 	{
 		obj_type => "ITEM",
@@ -43995,12 +44007,13 @@
 		user_level => "CLI_LEVEL_CONFIG",
 		help_string => "Clear all dynamic GENEVE forwarding entries",
 		function_name => "clear_geneve_forwarding_dynamic",
-		function_args => [ {
-		                     type => "U32",
-				     help_string => "VNI number",
-				     optional => "NO",
-				 },
-			 ],
+		function_args => [
+							{
+								type => "U32",
+								help_string => "VNI number",
+								optional => "NO",
+							}
+						]
 	},
 # geneve end
 
@@ -44052,7 +44065,7 @@
 		user_level => "CLI_LEVEL_CONFIG",
 		help_string => "   Configure XMLRPC Port",
 		function_name => "xmlrpc_port",
-		function_args => [ {
+		function_args => [{
 		                     type => "U16",
 				     help_string => "XMLRPC port (1025-65000, default = 9999)",
 				     optional => "NO",
@@ -44091,7 +44104,7 @@
 		user_level => "CLI_LEVEL_CONFIG",
 		help_string => "   Only accept connections at one specific IP address",
 		function_name => "xmlrpc_ip",
-		function_args => [ {
+		function_args => [{
 								type => "IPADDR",
 								help_string => "IP address to access XMLRPC",
 								optional => "NO",
@@ -44563,7 +44576,7 @@
 		cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL",
 		user_level => "CLI_LEVEL_ENABLE",
 		function_name => "debug_trace_ssl",
-		function_args => [ {
+		function_args => [{
 				     type => "STRING",
 				     help_string => "encrypt or plain(plain isn't supported for real host)",
 				     optional => "NO",
@@ -44609,7 +44622,7 @@
 	#	cmd_attribute => "CMD_ARRAYOS|CMD_SPROXY|CMD_NORMAL|CMD_KILLABLE|CMD_NON_MORE",
 	#	user_level => "CLI_LEVEL_ENABLE",
 	#	function_name => "debug_trace_live",
-	#	function_args => [ {
+	#	function_args => [{
 	#			     type => "STRING",
 	#			     help_string => "interface name",
 	#			     optional => "NO",
Index: /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_api.symlist
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_api.symlist	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_api.symlist	(working copy)
@@ -388,4 +388,6 @@
 slb_proxy_protocol_v2_flags
 if_dpdk_set_ha_hb_port_if
 diameter_config_shm_attach
-cloud_platform
\ No newline at end of file
+cloud_platform
+geneve_get_random_mac_addr
+if_dpdk_pack_geneve_head
\ No newline at end of file
Index: /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk.c	(working copy)
@@ -71,6 +71,7 @@
 #include <click/app/util/feactl_kern.h>
 #include <click/netinet/click_segment.h>
 #include <net/if_vxlan.h>
+#include <net/if_geneve.h>
 #include <click/app/ha/ha_misc.h>
 
 int atcp_dpdk_output(struct ifnet *ifp, struct mbuf *m);
@@ -2103,6 +2104,91 @@
 	}
 }
 
+#define RTE_MBUF_GENEVE_HEADER_LEN (sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr) + sizeof(struct geneve_header))
+
+void
+if_dpdk_veth_geneve_egress(void **pkts_burst, int pkts_num)
+{
+	int i;
+	int ip_cksum, tcp_cksum, udp_cksum;
+	int vni;
+	int error;
+	struct ifnet *ifp;
+	struct ip *ip;
+	struct ether_header *eh;
+	struct udphdr *udp;
+	struct geneve_header *gh;
+	struct mbuf *m;
+
+	for (i = 0; i < pkts_num; i++) {
+		eh = (struct ether_header *)if_dpdk_eth_mbuf_data(pkts_burst[i]);
+
+		if (mac_cmp(eh->ether_shost, geneve_parent_mac_addr_host) || mac_cmp(eh->ether_dhost, geneve_parent_mac_addr_user)) {
+			if_dpdk_eth_free_mbuf(pkts_burst[i]);
+			continue;
+		}
+
+		if (eh->ether_type != htons(ETHERTYPE_IP)) {
+			//ipv6
+			if_dpdk_eth_free_mbuf(pkts_burst[i]);
+			continue;
+		} 
+
+		ip = (struct ip *)((char *)eh + sizeof(struct ether_header));
+
+		if (ip->ip_src.s_addr != geneve_parent_ip_host_addr || ip->ip_dst.s_addr != geneve_parent_ip_user_addr) {
+			if_dpdk_eth_free_mbuf(pkts_burst[i]);
+			continue;
+		}
+
+		udp = (struct udphdr *)((char *)ip + (ip->ip_hl << 2));
+
+		if (ntohs(udp->uh_dport) != GENEVE_TUNNEL_DPORT) {
+			if_dpdk_eth_free_mbuf(pkts_burst[i]);
+			continue;
+		}
+	
+		m = m_buffer(if_dpdk_eth_mbuf_len(pkts_burst[i]) - RTE_MBUF_GENEVE_HEADER_LEN);
+		if (!m) {
+			if_dpdk_eth_free_mbuf(pkts_burst[i]);
+			continue;
+		}
+
+		memcpy(mtod(m, caddr_t), (char *)if_dpdk_eth_mbuf_data(pkts_burst[i]) + RTE_MBUF_GENEVE_HEADER_LEN, \
+				if_dpdk_eth_mbuf_len(pkts_burst[i]) - RTE_MBUF_GENEVE_HEADER_LEN);
+		
+		if_dpdk_eth_get_csum_flags(pkts_burst[i], &ip_cksum, &tcp_cksum, &udp_cksum);
+		if (ip_cksum) {
+			m->m_pkthdr.csum_flags |= CSUM_IP;
+		}
+
+		if (tcp_cksum) {
+			m->m_pkthdr.csum_flags |= CSUM_TCP;
+		} else if (udp_cksum) {
+			m->m_pkthdr.csum_flags |= CSUM_UDP;
+		}
+
+		gh = (struct geneve_header *)((char *)udp + sizeof(struct udphdr));
+			
+		if (gh->ver != htons(GENEVE_VER) ||
+			gh->vni & ~htonl(GENEVE_VNI_MASK) ||
+			gh->proto_type != htons(ETHERTYPE_TRANSETHER)) {
+			if_dpdk_eth_free_mbuf(pkts_burst[i]);
+			continue;
+		}
+
+		vni = ntohl(gh->vni) >> GENEVE_HDR_VNI_SHIFT;
+
+		ifp = get_geneve_ifp(vni);
+		if (!ifp) {
+			if_dpdk_eth_free_mbuf(pkts_burst[i]);
+		}
+
+		ifp->atcp_if_output(ifp, m);
+		if_dpdk_eth_free_mbuf(pkts_burst[i]);
+	}
+}
+
 void dpdk_kni_egress(void *arg)
 {
 	int i, pkts_num;
@@ -2143,6 +2229,14 @@
 		}
 	}
 
+	if (dpdk_geneve_parent_context) {
+		pkts_num = if_dpdk_eth_kni_pkts_get(dpdk_geneve_parent_context, pkts_burst);
+		if (pkts_num > 0) {
+			if_dpdk_veth_geneve_egress(pkts_burst, pkts_num);
+		}
+	}
+
+	// geneve_veth_egress();
 }
 
 uint16_t
@@ -2187,6 +2281,55 @@
 	return (sizeof(struct ether_header) + sizeof(struct ip)+ sizeof(struct udphdr)+ sizeof(struct vxlan_header));
 }
 
+uint16_t
+if_dpdk_pack_geneve_head(void *header, void *geneve_sc, uint32_t vni, struct mbuf *m)
+{
+	struct ip* ip;
+	struct udphdr *udp;
+	struct geneve_header *gh;
+	struct ether_header *eh;
+	uint16_t len;
+
+	GENEVE_DBG_ENTER("vni: %d, m: 0x%p", vni, m);
+
+	eh = (struct ether_header *)header;
+	eh->ether_type = htons(ETHERTYPE_IP);
+	memcpy(eh->ether_shost, geneve_parent_mac_addr_user, ETHER_ADDR_LEN);
+	memcpy(eh->ether_dhost, geneve_parent_mac_addr_host, ETHER_ADDR_LEN);
+
+	ip = (struct ip *)((char *)eh + sizeof(struct ether_header));
+	udp =  (struct udphdr *)((char *)ip + sizeof(struct ip));
+
+	udp->uh_sport = htons(GENEVE_TUNNEL_SPORT);
+	udp->uh_dport = htons(GENEVE_TUNNEL_DPORT);
+	len = sizeof(struct udphdr) + sizeof(struct geneve_header) + m->m_pkthdr.len + ETHER_HDR_LEN;
+	udp->uh_ulen = htons(len);
+	udp->uh_sum = 0;
+
+	ip->ip_v = IPVERSION;
+	ip->ip_hl = 0x5; /* 20 >> 2 */
+	ip->ip_tos = 0;
+	ip->ip_len = htons((len + sizeof(struct ip)));
+	ip->ip_off = 0;
+	ip->ip_ttl = 0xff;
+	ip->ip_p = IPPROTO_UDP;
+	ip->ip_src.s_addr = geneve_parent_ip_user_addr;
+	ip->ip_dst.s_addr = geneve_parent_ip_host_addr;
+	ip->ip_sum = 0;
+	ip->ip_sum = in_cksum_hdr(ip);
+
+	gh = (struct geneve_header *)((char *)udp + sizeof(struct udphdr));
+	gh->ver = htons(GENEVE_VER);
+	gh->opt_len = 0;
+	gh->oam = 0;
+	gh->critical = 0;
+	gh->rsvd = 0;
+	gh->proto_type = htons(ETHERTYPE_TRANSETHER);
+	gh->vni = htonl(vni << GENEVE_HDR_VNI_SHIFT);
+
+	return (sizeof(struct ether_header) + sizeof(struct ip)+ sizeof(struct udphdr)+ sizeof(struct geneve_header));
+}
+
 extern void *vlan_get_ctx(void *ifv);
 void dpdk_kni_ingress(struct mbuf* m)
 {
@@ -2195,11 +2338,12 @@
 	BOND_ADAPTER *bond_sc = NULL;
 	void *vlan_sc = NULL;
 	void *vxlan_sc = NULL;
+	void *geneve_sc = NULL;
 	void *pre_mbuf = NULL;
 	void *data_p;
 	int data_len;
 	int vlan_head = 0;
-	
+
 	if (ifp) {
 		switch (ifp->if_mode) {
 			case IF_MODE_DPDK:
@@ -2284,6 +2428,28 @@
 						      &pre_mbuf, data_p, data_len, m->m_next, &vlan_head) < 0) {
 							break;
 						}
+					}
+				}
+				break;
+			case IF_MODE_GENEVE:
+				geneve_sc = ifp->if_softc;
+				if (geneve_sc) {
+					if ((m!= NULL) && (m->m_flags & M_PKTHDR)) {
+						if_dpdk_veth_geneve_head_ingress(m, geneve_get_ctx_by_sc(geneve_sc), geneve_sc, &pre_mbuf);
+					}
+
+					for (; m != NULL; m = m->m_next) {
+						if (m->m_flags & M_PKTHDR) {
+							data_p = (char *)(m->m_data) - ETHER_HDR_LEN;
+							data_len = m->m_len + ETHER_HDR_LEN;
+						} else {
+							data_p = m->m_data;
+							data_len = m->m_len;
+						}
+						if (if_dpdk_eth_kni_ingress(geneve_get_ctx_by_sc(geneve_sc),
+						      &pre_mbuf, data_p, data_len, m->m_next, &vlan_head) < 0) {
+							break;
+						}
 					}
 				}
 				break;
Index: /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk_host.h
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk_host.h	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk_host.h	(working copy)
@@ -494,6 +494,15 @@
 extern int vxlan_parent_ip_host_addr;
 extern int max_vxlan;
 
+#define geneve_parent_ip_user "192.0.2.1"
+#define geneve_parent_ip_host "192.0.2.2"
+
+extern struct if_dpdk_host_context* dpdk_geneve_parent_context;
+extern uint8_t geneve_parent_mac_addr_user[ETHER_ADDR_LEN];
+extern uint8_t geneve_parent_mac_addr_host[ETHER_ADDR_LEN];
+extern int geneve_parent_ip_user_addr;
+extern int geneve_parent_ip_host_addr;
+
 struct if_dpdk_host_context;
 struct rte_mbuf;
 
@@ -548,8 +557,12 @@
 struct if_dpdk_host_context *if_dpdk_create_bond_kni_if(char *if_name, int port_id);
 struct if_dpdk_host_context *if_dpdk_create_vlan_kni_if(char *if_name, int vlan_id);
 struct if_dpdk_host_context *if_dpdk_create_vxlan_ctx(char *veth_name, int port_id);
+struct if_dpdk_host_context *if_dpdk_create_geneve_ctx(char *veth_name, int port_id);
 void if_dpdk_set_vxlan_vni(void *ctx, uint32_t vni);
 void if_dpdk_delete_vxlan_ctx(int port_id);
+void if_dpdk_set_geneve_vni(void *ctx, uint32_t vni);
+void if_dpdk_delete_geneve_ctx(int port_id);
+void if_dpdk_veth_geneve_head_ingress(void *m, struct if_dpdk_host_context *ctx, void *vxlan_sc, void **buf);
 int if_dpdk_create_dpdk_virtio_user(struct if_dpdk_host_context *ctx);
 int if_dpdk_eth_kni_pkts_get(struct if_dpdk_host_context *ctx, void **pkts_burst);
 int if_dpdk_eth_mbuf_len(void *m);
Index: /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk_host.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk_host.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_if_dpdk_host.c	(working copy)
@@ -172,6 +172,7 @@
 	IF_DPDK_TYPE_BOND,
 	IF_DPDK_TYPE_VLAN,
 	IF_DPDK_TYPE_VXLAN,
+	IF_DPDK_TYPE_GENEVE,
 	IF_DPDK_TYPE_MAX
 };
 
@@ -202,6 +203,10 @@
 			struct if_dpdk_host_context *vxlan_parent_ctx;
 			uint32_t vni;
 		};  /*for vxlan*/
+		struct {
+			struct if_dpdk_host_context *geneve_parent_ctx;
+			uint32_t geneve_vni;
+		};  /* for geneve */
 	};
 	struct if_dpdk_host_tx_queue tx_queue[ATCP_L4_MAXTHREADS];
 	int unit;
@@ -224,10 +229,12 @@
 extern int if_dpdk_get_bind_port_queue_index(int port_id, int queue_id);
 struct mbuf;
 extern uint16_t if_dpdk_pack_vxlan_head(void *header, void *vxlan_sc, uint32_t vni, struct mbuf* m);
+extern uint16_t if_dpdk_pack_geneve_head(void *header, void *geneve_sc, uint32_t vni, struct mbuf* m);
 
 #define MAX_NIC 36
 #define BOND_MAX_PSEUDO_CARDS 8
 #define MAX_VXLAN   (32768)
+#define MAX_GENEVE  (2048)
 struct if_dpdk_host_context* dpdk_host_context_arr[MAX_NIC];
 struct if_dpdk_host_context* dpdk_bond_context_arr[BOND_MAX_PSEUDO_CARDS];
 struct if_dpdk_host_context* dpdk_vlan_context_arr[4096];
@@ -240,7 +247,12 @@
 uint8_t vxlan_parent_mac_addr_user[ETHER_ADDR_LEN];
 int vxlan_parent_ip_user_addr = 0x010100C0;
 int vxlan_parent_ip_host_addr = 0x020100C0;
-
+struct if_dpdk_host_context* dpdk_geneve_context_arr[MAX_GENEVE];
+struct if_dpdk_host_context* dpdk_geneve_parent_context = NULL;
+uint8_t geneve_parent_mac_addr_host[ETHER_ADDR_LEN];
+uint8_t geneve_parent_mac_addr_user[ETHER_ADDR_LEN];
+int geneve_parent_ip_user_addr = 0x010200C0;
+int geneve_parent_ip_host_addr = 0x020200C0;
 
 pthread_mutex_t reset_mutex[MAX_NIC];
 uint8_t tq_enter_flag[ATCP_MAXTHREADS][MAX_NIC];
@@ -1377,6 +1389,31 @@
 	return;
 }
 
+void
+if_dpdk_veth_geneve_head_ingress(void *m, struct if_dpdk_host_context *ctx, void *geneve_sc, void **buf)
+{
+	unsigned num;
+	struct rte_mbuf *m1;
+	void *rmdptr;
+	void *eh = NULL;
+	uint16_t len = 0;
+
+	m1 =  rte_pktmbuf_alloc(ctx->kni_mbpool);
+	*buf = m1;
+
+	if (unlikely(m1 == NULL)) {
+		printf("Alloc new rte_mbuf failed!\n");
+		return;
+	}
+
+	eh = rte_pktmbuf_mtod(m1, void *);
+	len = if_dpdk_pack_geneve_head(eh, geneve_sc, ctx->geneve_vni, m);
+	m1->data_len = (uint16_t)(m1->data_len + len);
+	m1->pkt_len  = (m1->pkt_len + len);
+
+	return;
+}
+
 static int 
 if_dpdk_pktmbuf_memcpy(struct rte_mbuf *m, void *data, int len)
 {
@@ -1458,6 +1495,10 @@
 		ctx = ctx->vxlan_parent_ctx;
 	}
 
+	if (ctx->if_dpdk_type == IF_DPDK_TYPE_GENEVE) {
+		ctx = ctx->geneve_parent_ctx;
+	}
+
 	if (more == NULL) {
 		rte_spinlock_lock(&ctx->vio_usr_tx_lock);
 		num = rte_eth_tx_burst(ctx->vio_usr_port_id, 0, &m1, 1);
@@ -1962,6 +2003,8 @@
 		if_dpdk_type = IF_DPDK_TYPE_VLAN;
 	} else if (strcmp("vxlan", type) == 0) {
 		if_dpdk_type = IF_DPDK_TYPE_VXLAN;
+	} else if (strcmp("geneve", type) == 0) {
+		if_dpdk_type = IF_DPDK_TYPE_GENEVE;
 	} else {
 		return NULL;
 	}
@@ -1985,7 +2028,6 @@
 		printf("create virtio_user for %s port %u failed\n", type, port_id);
 		goto fail;
 	}
-	
 	return ctx;
 
 fail:
@@ -2098,6 +2140,34 @@
 	}
 }
 
+void 
+if_dpdk_set_geneve_vni(void *ctx, uint32_t vni)
+{
+	struct if_dpdk_host_context *tmp = ctx;
+
+	if (tmp) {
+		tmp->geneve_vni = vni;
+	}
+}
+
+struct if_dpdk_host_context *
+if_dpdk_create_geneve_ctx(char *veth_name, int port_id)
+{
+	if (!dpdk_geneve_context_arr[port_id]) {
+		dpdk_geneve_context_arr[port_id] = if_dpdk_create_kni_if(veth_name, port_id, "geneve");
+	}
+
+	return dpdk_geneve_context_arr[port_id];
+}
+
+void 
+if_dpdk_delete_geneve_ctx(int port_id)
+{
+	if (dpdk_geneve_context_arr[port_id]) {
+		if_dpdk_delete_if(dpdk_geneve_context_arr[port_id]);
+		dpdk_geneve_context_arr[port_id] = NULL;
+	}
+}
 
 int 
 if_dpdk_veth_set_mac(char *p_ifname, uint8_t *mac)
@@ -2124,6 +2194,8 @@
 #define RTE_VIRTIO_USER_QUEUE_SIZE_BOND		(2048)
 #define RTE_VIRTIO_USER_QUEUES_VXLAN		(QUEUE_MAX)
 #define RTE_VIRTIO_USER_QUEUE_SIZE_VXLAN	(2048)
+#define RTE_VIRTIO_USER_QUEUES_GENEVE		(QUEUE_MAX)
+#define RTE_VIRTIO_USER_QUEUE_SIZE_GENEVE	(2048)
 extern uint8_t eth_dev_last_created_port;
 
 int 
@@ -2185,7 +2257,22 @@
 			ctx->vxlan_parent_ctx = dpdk_vxlan_parent_context;
 			return 0;
 		}
-		
+		break;
+	case IF_DPDK_TYPE_GENEVE:
+		if (!dpdk_geneve_parent_context) {
+			domain = 0;
+			geneve_get_random_mac_addr(mac_addr);
+			bcopy(mac_addr, geneve_parent_mac_addr_host, ETHER_ADDR_LEN);
+			queues = RTE_VIRTIO_USER_QUEUES_GENEVE;
+			queue_size = RTE_VIRTIO_USER_QUEUE_SIZE_GENEVE;
+			snprintf(virtio_user_name, RTE_VIRTIO_USER_NAME_SIZE, "virtio_user_geneve%u", port_id);
+			snprintf(virtio_user_args, RTE_VIRTIO_USER_ARGS_SIZE, 
+			 	 	"path=/dev/vhost-net,queues=%d,queue_size=%d,iface=%s",
+				 	queues, queue_size, ctx->veth_name);
+		} else {
+			ctx->geneve_parent_ctx = dpdk_geneve_parent_context;
+			return 0;
+		}
 		break;
 	default:
 		return 0;
@@ -2224,7 +2311,9 @@
 		}
 	}
 
-	if ((ctx->if_dpdk_type == IF_DPDK_TYPE_NIC) || (ctx->if_dpdk_type == IF_DPDK_TYPE_VXLAN)) {
+	if ((ctx->if_dpdk_type == IF_DPDK_TYPE_NIC) || 
+		(ctx->if_dpdk_type == IF_DPDK_TYPE_VXLAN) ||
+		(ctx->if_dpdk_type == IF_DPDK_TYPE_GENEVE)) {
 		if (if_dpdk_veth_set_mac(ctx->veth_name, mac_addr) < 0) {
 			printf("failed to set mac for %s(port %u)\n", virtio_user_name, virtio_user_port_id);
 			return -1;
@@ -2238,11 +2327,9 @@
 
 	ctx->vio_usr_port_id = virtio_user_port_id;
 	ctx->vio_usr_vqueues = queues;
-	
 	return 0;
 
 fail:
-
 	return -1;
 }
 
@@ -2256,6 +2343,9 @@
 	case IF_DPDK_TYPE_VXLAN:
 		snprintf(virtio_user_name, RTE_VIRTIO_USER_NAME_SIZE, "virtio_user_vxlan%u", port_id);
 		break;
+	case IF_DPDK_TYPE_GENEVE:
+		snprintf(virtio_user_name, RTE_VIRTIO_USER_NAME_SIZE, "virtio_user_geneve%u", port_id);
+		break;
 	default:
 		return;
 	}
Index: /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_machdep.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_machdep.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/lib/libuinet-atcp/lib/libuinet/uinet_machdep.c	(working copy)
@@ -329,6 +329,7 @@
 	char configstr[8];
 	char alias[16];
 	char vxlan_parent[16];
+	char geneve_parent[16];
 	char cmd[128] = {0};
 	struct ether_addr ea;
 	char mac[17] = {0};
@@ -388,6 +389,27 @@
 	ether_ntoa_r(&ea, mac);
 	snprintf(cmd, sizeof(cmd), "arp -s %s %s", vxlan_parent_ip_user, mac);
 	u_system(cmd);
+
+	/* create geneve parent, use of linux */
+	snprintf(geneve_parent, sizeof(geneve_parent), "geneve_parent");
+	dpdk_geneve_parent_context = if_dpdk_create_kni_if(geneve_parent, -1, "geneve");
+	if (!dpdk_geneve_parent_context) {
+		printf("create geneve veth interface failed!\n");
+		return;
+	}
+
+	snprintf(cmd, sizeof(cmd), "ip addr add %s/24 dev %s", geneve_parent_ip_host, geneve_parent);
+	u_system(cmd);
+	geneve_get_random_mac_addr(geneve_parent_mac_addr_user);
+	snprintf(cmd, sizeof(cmd), "ip link set dev geneve_parent up");
+	u_system(cmd);
+	bcopy(geneve_parent_mac_addr_user, ea.octet, ETHER_ADDR_LEN);	
+	ether_ntoa_r(&ea, mac);
+	snprintf(cmd, sizeof(cmd), "arp -s %s %s", geneve_parent_ip_user, mac);
+	u_system(cmd);
+	snprintf(cmd, sizeof(cmd), "ip route add %s dev %s", geneve_parent_ip_user, geneve_parent);
+	u_system(cmd);
+
 	return;
 }
 
Index: /branches/rel_apv_10_7/usr/click/tools/sysv_click
===================================================================
--- /branches/rel_apv_10_7/usr/click/tools/sysv_click	(revision 39181)
+++ /branches/rel_apv_10_7/usr/click/tools/sysv_click	(working copy)
@@ -394,6 +394,9 @@
 		fi 
 	fi
 
+	# install geneve kmod
+	modprobe geneve
+
 	if [ ! -f "/lib64/libnfnetlink.so" ]; then
 		ln -s /lib64/libnfnetlink.so.0.2.0 /lib64/libnfnetlink.so
 	fi
@@ -843,6 +846,8 @@
 		firewall-cmd --direct --add-rule ipv4 filter INPUT 0 --protocol ip --source 192.0.0.1 -j ACCEPT
 		#rule for linux kni
 		firewall-cmd --direct --add-rule ipv4 filter INPUT 0 --protocol udp --source 192.0.1.1 --destination 192.0.1.2 --sport 4789 --dport 4789 -j ACCEPT
+		#rule for linux kni
+		firewall-cmd --direct --add-rule ipv4 filter INPUT 0 --protocol udp --dport 6081 -j ACCEPT
 	fi
 	/usr/sbin/ip6tables -t raw -D PREROUTING -m rpfilter --invert -j DROP
 
Index: /branches/rel_apv_10_7/usr/src/sys/click/app/proxy/proxy_shm.h
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/app/proxy/proxy_shm.h	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/click/app/proxy/proxy_shm.h	(working copy)
@@ -265,4 +265,8 @@
 #define VXLAN_SHM_KEY		8132
 #define VXLAN_TUN_SHM_KEY	8131
 
+/* geneve support */
+#define GENEVE_SHM_KEY		8133
+#define GENEVE_TUN_SHM_KEY	8134
+
 #endif				/* ifndef (_CA_SHM_H_) */
Index: /branches/rel_apv_10_7/usr/src/sys/click/net/an_ethersubr.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/net/an_ethersubr.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/click/net/an_ethersubr.c	(working copy)
@@ -637,7 +637,7 @@
 		return ;
 	}
 	
-	for (i = MAX_NIC; i < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + max_vxlan; i++) {
+	for (i = MAX_NIC; i < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + max_vxlan + MAX_GENEVE; i++) {
 		if ((cafw_p->ifnodes[i] == NULL) || (cafw_p->ifnodes[i]->if_name[0] == 0)) {
 			continue;
 		}
Index: /branches/rel_apv_10_7/usr/src/sys/click/net/click_ether.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/net/click_ether.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/click/net/click_ether.c	(working copy)
@@ -636,6 +636,9 @@
 extern int vxlan_enable;
 extern int vxlan_port;
 
+extern int geneve_enable;
+extern int geneve_port;
+
 static struct in_addr ssh_ip = {0};
 SYSCTL_STRUCT(_net_inet_clicktcp, OID_AUTO, ssh_ip_config, CTLFLAG_RW, &ssh_ip, in_addr, "SSH ip configuration");
 static struct in6_addr ssh_ip6 = IN6ADDR_ANY_INIT;
@@ -2074,6 +2077,12 @@
 			} else {
 				return CLICKTCP_NOT_OUR_PACKET;
 			}
+
+			if (geneve_enable && geneve_port == ntohs(udph->uh_dport)) {
+				printf("geneve mcast packets comes in, dst %x, src %x, sport %d, dport %d.\n", iph->ip_dst.s_addr, iph->ip_src.s_addr, udph->uh_sport, udph->uh_dport);
+			} else {
+				return CLICKTCP_NOT_OUR_PACKET;
+			}
 		}
 
 		*l4_hdr = (caddr_t)udph;
@@ -2398,6 +2407,7 @@
 	struct udphdr *udp = NULL;
 	int nxt = 0;
 	int is_vxlan_port = 0;
+	int is_geneve_port = 0;
 
 	if (m->m_len < sizeof(struct ip6_hdr)) {
 		return CLICKTCP_NOT_OUR_PACKET;
@@ -2422,8 +2432,13 @@
 		is_vxlan_port = 1;
 	}
 
+	if (geneve_enable && nxt == IPPROTO_UDP && geneve_port == ntohs(((struct udphdr *)(*l4_hdr))->uh_dport)) {
+		/* geneve mcast packet is our packet */
+		is_geneve_port = 1;
+	}
+
 	/* check src/dst address, only global unicast, link-local and loopback address can be handled by us */
-	if ((IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && !is_vxlan_port)  ||
+	if ((IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && !is_vxlan_port && !is_geneve_port)  ||
 	   IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) ||
 	   IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst) ||
 	   IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst) ||
@@ -2437,7 +2452,7 @@
 	   return CLICKTCP_NOT_OUR_PACKET; 
 	}
 
-	if ((m->m_flags & (M_BCAST|M_MCAST)) && !is_vxlan_port) {
+	if ((m->m_flags & (M_BCAST|M_MCAST)) && !is_vxlan_port && !is_geneve_port) {
 		return CLICKTCP_NOT_OUR_PACKET;
 	}
 
Index: /branches/rel_apv_10_7/usr/src/sys/click/net/if_cafw.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/net/if_cafw.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/click/net/if_cafw.c	(working copy)
@@ -2006,7 +2006,7 @@
 	}
 	
 	/* get all interfaces now */
-	for (nic = 0; nic < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + max_vxlan; nic++) {
+	for (nic = 0; nic < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + max_vxlan + MAX_GENEVE; nic++) {
 		ca_p->ifnodes[nic] = cafw_ifnode_new(nic);
 	}
 
@@ -2185,10 +2185,15 @@
 	}
 	/*Link Aggregation,beisf,20051230*/
 	/*vxlan_support*/
-	else if (nic >= CAFW_VXLAN_OFFSET) {
+	else if (nic >= CAFW_VXLAN_OFFSET && nic < CAFW_GENEVE_OFFSET) {
 		sprintf(buf, "vxlan%d", nic - (CAFW_VXLAN_OFFSET));
 		return (uint64_t)ifunit(buf);
 	}
+	/* geneve support */
+	else if (nic >= CAFW_GENEVE_OFFSET) {
+		sprintf(buf, "geneve%d", nic - (CAFW_GENEVE_OFFSET));
+		return (uint64_t)ifunit(buf);
+	}
 
 	return 0;
 }
@@ -2205,7 +2210,7 @@
 
 	ca_p = &clickaddresses->cafw_share;
 
-	for (nic = 0; nic < MAX_NIC + BOND_MAX_PSEUDO_CARDS + MAX_VLAN + MAX_VXLAN_TEST; nic++) {
+	for (nic = 0; nic < MAX_NIC + BOND_MAX_PSEUDO_CARDS + MAX_VLAN + MAX_VXLAN_TEST + MAX_GENEVE; nic++) {
 		struct ifnet *cur_ifp;
 		ifn_p = ca_p->ifnodes[nic];
 		if (ifn_p == NULL) {
@@ -2353,7 +2358,7 @@
 	
 	/* update all interfaces associated with the list id */
 	ret = 0;
-	for (nic = 0; nic < MAX_NIC + BOND_MAX_PSEUDO_CARDS + MAX_VLAN + MAX_VXLAN_TEST; nic++) {
+	for (nic = 0; nic < MAX_NIC + BOND_MAX_PSEUDO_CARDS + MAX_VLAN + MAX_VXLAN_TEST + MAX_GENEVE; nic++) {
 		ifn_p = ca_p->ifnodes[nic];
 		if (ifn_p == NULL || !cafw_agroup_has(ifn_p, list_p->list)) {
 			continue;
@@ -2667,7 +2672,7 @@
 	
 	ca_p = &clickaddresses->cafw_share;
 	/* all interfaces */
-	for (nic = 0; nic < MAX_NIC + BOND_MAX_PSEUDO_CARDS + MAX_VLAN + MAX_VXLAN_TEST; nic++) {
+	for (nic = 0; nic < MAX_NIC + BOND_MAX_PSEUDO_CARDS + MAX_VLAN + MAX_VXLAN_TEST + MAX_GENEVE; nic++) {
 		ifn_p = ca_p->ifnodes[nic];
 		if (ifn_p == NULL){
 			continue;
@@ -3051,7 +3056,7 @@
 
 	ca_p = &clickaddresses->cafw_share;
 	/* clear all interfaces */
-	for (nic = 0; nic < MAX_NIC + BOND_MAX_PSEUDO_CARDS + MAX_VLAN + MAX_VXLAN_TEST; nic++) {
+	for (nic = 0; nic < MAX_NIC + BOND_MAX_PSEUDO_CARDS + MAX_VLAN + MAX_VXLAN_TEST + MAX_GENEVE; nic++) {
 		ifn_p = ca_p->ifnodes[nic];
 		if (ifn_p == NULL || !ifn_p->if_on){
 			continue;
Index: /branches/rel_apv_10_7/usr/src/sys/click/netinet/cafw.h
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/netinet/cafw.h	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/click/netinet/cafw.h	(working copy)
@@ -21,6 +21,7 @@
 #define MAX_MNET   		(32 + 4094) 
 #define MAX_VXLAN		(32768)	/* from ip.h */
 #define MAX_VXLAN_TEST	MAX_VXLAN	/* from ip.h */
+#define MAX_GENEVE		(2048)	/* from ip.h */
 
 /* Link Aggregation, lingx, 20051228 */
 #ifndef BOND_MAX_PSEUDO_CARDS 
@@ -244,7 +245,7 @@
 
 /* Link Aggregation, lingx, 20051228 */
 struct cafw_share { 
-	cafw_ifnode_t		*ifnodes[MAX_NIC+MAX_VLAN+BOND_MAX_PSEUDO_CARDS+MAX_VXLAN_TEST];	/* all interfaces */
+	cafw_ifnode_t		*ifnodes[MAX_NIC+MAX_VLAN+BOND_MAX_PSEUDO_CARDS+MAX_VXLAN_TEST+MAX_GENEVE];	/* all interfaces */
 	cafw_listaddr_t		alists[MAX_LIST_NUM];	/* all accesslists */
 	struct fw_queue		fw_queue;	/* for logging */
 	struct cafw_stats       total_stats;
@@ -253,6 +254,7 @@
 #define CAFW_VLAN_OFFSET MAX_NIC
 #define CAFW_BOND_OFFSET (MAX_NIC + MAX_VLAN)
 #define CAFW_VXLAN_OFFSET (MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS)
+#define CAFW_GENEVE_OFFSET (MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + MAX_VXLAN_TEST)
 };
 /* Link Aggregation, end */
 
Index: /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_ports.h
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_ports.h	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_ports.h	(working copy)
@@ -53,8 +53,9 @@
 #define GSLB_MCAST_PORT        65533
 #define ENGLOG_KERN_PORT       65534
 
-
-
+/* The port used for geneve linux virtio*/
+#define	GENEVE_TUNNEL_SPORT	6081
+#define	GENEVE_TUNNEL_DPORT	6081
 
 /* The port used for vxlan linux virtio*/
 #define	VXLAN_TUNNEL_SPORT	4789
@@ -62,8 +63,3 @@
 
 
 #endif /* _NETINET_CLICK_PORTS_H */
-
-
-
-
-
Index: /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_udp.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_udp.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_udp.c	(working copy)
@@ -88,6 +88,9 @@
 #include "kernelWrapper.h"
 #include "epolicy_engine.h"
 
+/* geneve support */
+#include <net/if_geneve.h>
+
 MALLOC_DECLARE(M_DOMAIN_EROUTE);
 
 /* This is enough to hold a full 65535 byte packet cut into 576 byte chunks */
@@ -916,6 +919,64 @@
 	return;
 }
 
+int geneve_port = GENEVE_DEFAULT_PORT;
+SYSCTL_INT(_net_inet_clicktcp, OID_AUTO, geneve_port, CTLFLAG_RW, &geneve_port, 0, "geneve UDP port");
+
+int geneve_enable = GENEVE_DISABLE;
+SYSCTL_INT(_net_inet_clicktcp, OID_AUTO, geneve_enable, CTLFLAG_RW, &geneve_enable, 0, "geneve enable");
+
+/* Check geneve hdr and learn to fwd table: Inner Source MAC ==> Outter Source IP */
+void clicktcp_geneve_input(struct mbuf* m, int isipv6, struct ip* ip, struct ip6_hdr* ip6, struct udphdr* udp)
+{
+	struct geneve_header *gh, genevehdr;
+	uint32_t vni;
+	int hdr_len;
+
+	M_ASSERTPKTHDR(m);
+
+	GENEVE_DBG_ENTER("m: %p, isipv6: %d, ip: %p, ip6: %p, udp: %p", m, isipv6, ip, ip6, udp);
+
+	if (isipv6) {
+		hdr_len = sizeof(struct ip6_hdr) + sizeof(struct udphdr);
+	} else {
+		hdr_len = sizeof(struct ip) + sizeof(struct udphdr);
+	}
+
+	if (m->m_pkthdr.len < hdr_len + sizeof(struct geneve_header)) {
+		goto out;
+	}
+
+	if (__predict_false(m->m_len < hdr_len + sizeof(struct geneve_header))) {
+		m_copydata(m, hdr_len, sizeof(struct geneve_header), (caddr_t)&genevehdr);
+		gh = &genevehdr;
+	} else {
+		gh = mtodo(m, hdr_len);
+	}
+
+	if (gh->ver != htons(GENEVE_VER) ||
+		gh->vni & ~htonl(GENEVE_VNI_MASK) ||
+		gh->proto_type != htons(ETHERTYPE_TRANSETHER)) {
+		goto out;
+	}
+
+	vni = ntohl(gh->vni) >> GENEVE_HDR_VNI_SHIFT;
+
+	/* Adjust to the start of the inner Ethernet frame. */
+	m_adj(m, hdr_len + sizeof(struct geneve_header));
+
+	geneve_learn_fwd(vni, m, ip, ip6, isipv6);
+
+	return;
+
+out:
+	if (m) {
+		GENEVE_DBG_ERR("bad geneve check, dropping mbuf 0x%p", m);
+		m_freem_atcp(m);
+	}
+
+	return;
+}
+
 /*
  * clickudp_input
  *
@@ -1085,6 +1146,16 @@
 		if (pcb != NULL) {
 			clickudp_cleanup_pcb(pcb);
 			clickpcb_delete((clickpcb_t *)pcb);
+		}
+		clicktcp_leave_func_void();
+	}
+
+	/* geneve process */
+	if (geneve_enable && (geneve_port == ntohs(udp->uh_dport))) {
+		clicktcp_geneve_input(m, isipv6, ip, ip6, udp);
+		if (pcb != NULL) {
+			clickudp_cleanup_pcb(pcb);
+			clickpcb_delete((clickpcb_t *)pcb);
 		}
 		clicktcp_leave_func_void();
 	}
Index: /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_usrreq.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_usrreq.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_usrreq.c	(working copy)
@@ -683,7 +683,7 @@
 	int      cnt = 0;
 	uint16_t nic;
 
-	for (nic = 1; nic < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + MAX_VXLAN_TEST; nic++) {
+	for (nic = 1; nic < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + MAX_VXLAN_TEST + MAX_GENEVE; nic++) {
 		if (VALID_IFNODE(clickaddresses->cafw_share.ifnodes[nic])) {
 			cnt++;
 		}
@@ -2085,7 +2085,7 @@
 	rs_vip = slb_get_rs_pure_count(NULL);
 
 	/* ethernet */
-	for (nic = 0; nic < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + MAX_VXLAN_TEST; nic++) {
+	for (nic = 0; nic < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + MAX_VXLAN_TEST + MAX_GENEVE; nic++) {
 		if (!VALID_IFNODE(clickaddresses->cafw_share.ifnodes[nic])) {
 			continue;
 		}
@@ -2126,7 +2126,7 @@
 	}
 
 	/* tcp */
-	for (nic = 0; nic < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + MAX_VXLAN_TEST; nic++) {
+	for (nic = 0; nic < MAX_NIC + MAX_VLAN + BOND_MAX_PSEUDO_CARDS + MAX_VXLAN_TEST + MAX_GENEVE; nic++) {
 		if (!VALID_IFNODE(clickaddresses->cafw_share.ifnodes[nic])) {
 			continue;
 		}		    
Index: /branches/rel_apv_10_7/usr/src/sys/modules/Makefile
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/modules/Makefile	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/modules/Makefile	(working copy)
@@ -151,6 +151,7 @@
 	if_tun \
 	if_vlan \
 	if_vxlan \
+	if_geneve \
 	${_igb} \
 	${_iir} \
 	${_imgact_binmisc} \
Index: /branches/rel_apv_10_7/usr/src/sys/net/if.h
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/net/if.h	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/net/if.h	(working copy)
@@ -176,7 +176,8 @@
 /*vxlan_support*/
 #define	IFF_VXLAN_BIND	0x10000000		/* vxlan associated*/
 #define	IFF_MNET		0x20000000		/* the interface has mnet */
-#define IFF_SHUTDOWN	0x40000000		/*the interface has shutdown*/	
+#define IFF_SHUTDOWN	0x40000000		/*the interface has shutdown*/
+#define	IFF_GENEVE_BIND	0x80000000		/* geneve associated*/	
 #endif /* ARRAYOS */
 
 #ifdef UINET
Index: /branches/rel_apv_10_7/usr/src/sys/net/if_ethersubr.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/net/if_ethersubr.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/net/if_ethersubr.c	(working copy)
@@ -101,6 +101,7 @@
 #include <click/app/spanport/span_port.h>
 #include <click/netinet/click_segment.h>
 #include <net/if_vxlan.h>
+#include <net/if_geneve.h>
 #include <click/app/ha/ha_misc.h>
 #include <click/app/lldp/lldp.h>
 #include <click/app/cm/sf_global.h>
@@ -1306,6 +1307,36 @@
 	}
 	/*vxlan L2 end*/
 
+	/* geneve L2 start */
+	/* promic must be set for local interface. No need for geneve-resided physical interface */
+	if (ifp->if_flags & IFF_GENEVE_BIND && ifp->geneve_vni != 0) {
+		struct ifnet *geneve_ifp;
+		struct mbuf *n;
+
+		geneve_ifp = geneve_local_learn(ifp, m);
+		if (!geneve_ifp) {
+			m_freem(m);
+			return;
+		}
+
+		switch(geneve_need_fwd(geneve_ifp, m)) {
+			case GENEVE_DST_REMOTE:
+				geneve_l2_fwd_local2tun(geneve_ifp, m, 0);
+				return;
+			case GENEVE_DST_FLOOD:
+				n = m_dup(m, M_NOWAIT);
+				geneve_l2_fwd_local2tun(geneve_ifp, n, 1);
+				break;
+			case GENEVE_DST_LOCAL:
+			default:
+				break;
+		}
+
+		/* if comes here, mean we received a packet from local vlan, change the rcvif to geneve */
+		ifp = geneve_ifp;
+	}
+	/* geneve L2 end */
+
 	/*
 	 * Reset layer specific mbuf flags to avoid confusing upper layers.
 	 * Strip off Ethernet header.
Index: /branches/rel_apv_10_7/usr/src/sys/net/if_geneve.h
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/net/if_geneve.h	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/net/if_geneve.h	(working copy)
@@ -1,36 +1,169 @@
-/*-
- * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org>
- * All rights reserved.
+/*------------------------------------------------------------------------------
+ * Copyright (C) 2025
+ * ArrayNetworks Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice unmodified, this list of conditions, and the following
- *    disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+ * modification is not permitted unless authorized in writing by a duly
+ * appointed officer of ArrayNetworks Inc. or its derivatives
+ *--------------------------------------------------------------------------- */
 
 #ifndef _NET_IF_GENEVE_H_
 #define _NET_IF_GENEVE_H_
 
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <net/ethernet.h>
+
 #include <net/if.h>
+#include <net/ethernet.h>
+
 #include <netinet/in.h>
+#include <netinet/udp.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+#define MAX_GENEVE	                     (2048)
+#define GENEVE_KNI_NAME_FMT	             ("atcp_geneve%d")
+#define GENEVE_KNI_NAME_LEN	             (32)
+
+#define GENEVE_DEFAULT_PORT              6081
+#define GENEVE_VNI_MIN                   1
+#define GENEVE_VNI_MAX                   (1 << 24)
+#define GENEVE_VNI_MASK                  (GENEVE_VNI_MAX - 1)
+#define GENEVE_HDR_VNI_SHIFT             (8)
+
+#define GENEVE_MAX_TUNNEL                64
+#define GENEVE_VNI_MAX_TUNNEL            12      /* Max tunnels a vni can reside on */
+#define MAX_TUNNEL_NAME_LEN              32
+
+#define GENEVE_SOCKADDR_IS_IPV4(_sin)  ((_sin)->sa.sa_family == AF_INET)
+#define GENEVE_SOCKADDR_IS_IPV6(_sin)  ((_sin)->sa.sa_family == AF_INET6)
+#define GENEVE_SOCKADDR_IS_IPV46(_sin) (GENEVE_SOCKADDR_IS_IPV4(_sin) || GENEVE_SOCKADDR_IS_IPV6(_sin))
+
+#define GENEVE_CMD_SET_VNI               0
+#define GENEVE_CMD_SET_REMOTE_ADDR       1
+#define GENEVE_CMD_SET_LEARN             2
+#define GENEVE_CMD_FTABLE_ENTRY_ADD      3
+#define GENEVE_CMD_FTABLE_ENTRY_REM      4
+
+#define GENEVE_VER                       0
+
+struct geneve_softc;
+LIST_HEAD(geneve_softc_head, geneve_softc);
+extern struct geneve_softc *geneve_softc_arr[MAX_GENEVE];
+extern struct geneve_softc_head geneve_sc_list;
+
+/* Geneve Header:
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |Ver|  Opt Len  |O|C|    Rsvd.  |          Protocol Type        |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |        Virtual Network Identifier (VNI)       |    Reserved   |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                    Variable Length Options                    |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Option Header:
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |          Option Class         |      Type     |R|R|R| Length  |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                      Variable Option Data                     |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+struct geneve_opt {
+    uint16_t opt_class;
+    uint8_t  type;
+    uint8_t  r1:1;
+    uint8_t  r2:1;
+    uint8_t  r3:1;
+    uint8_t  length:5;
+    uint8_t  opt_data[];
+} __packed;
+
+struct geneve_header {
+    uint8_t  ver:2;
+    uint8_t  opt_len:6;
+    uint8_t  oam:1;
+    uint8_t  critical:1;
+    uint8_t  rsvd:6;
+    uint16_t proto_type;
+    uint32_t vni;
+    /* uint8_t options[]; */
+} __packed;
+
+struct geneve_udphdr {
+    struct udphdr          uhdr;
+    struct geneve_header   ghdr;
+} __packed;
+
+union geneve_sockaddr {
+    struct sockaddr     sa;
+    struct sockaddr_in  in4;
+    struct sockaddr_in6 in6;
+};
+
+struct ifgenevecfg {
+    uint32_t              cfg_vni;
+    union geneve_sockaddr cfg_remote_sa;
+    uint8_t               cfg_learn;
+};
+
+struct ifgenevecmd {
+    uint32_t              cmd_flags;
+#define GENEVE_CMD_FLAG_FLUSH_ALL    0x0001
+#define GENEVE_CMD_FLAG_LEARN        0x0002
+    uint32_t              cmd_vni;
+    uint16_t              cmd_port;
+    uint8_t               cmd_mac[ETHER_ADDR_LEN];
+    union geneve_sockaddr cmd_sa;
+    char                  cmd_ifname[IFNAMSIZ];
+};
+
+enum {
+    GENEVE_DISABLE = 0,
+    GENEVE_ENABLE,
+};
+
+enum {
+    GENEVE_LEARN_OFF = 0,
+    GENEVE_LEARN_ON,
+};
+
+enum {
+    GENEVE_DST_LOCAL,
+    GENEVE_DST_REMOTE,
+    GENEVE_DST_FLOOD
+};
+
+enum {
+    GENEVE_DBG_OFF = 0,
+    GENEVE_DBG_ON,
+};
+
+#define GENEVE_DBG_ERR(fmt, ...) \
+    do { \
+        printf("%s(%d): " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+    } while (0)
+
+#define GENEVE_DBG_ENTER(fmt, ...) \
+    do {  \
+        int dbg = GENEVE_DBG_OFF; \
+        size_t len = sizeof(dbg); \
+        sysctlbyname("net.inet.clicktcp.geneve_debug", &dbg, &len, NULL, 0); \
+        if (dbg) { \
+            printf("%s(%d): " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+        } \
+    } while (0)
+
+#define GENEVE_DBG_INFO GENEVE_DBG_ENTER
+
+void geneve_veth_egress(void);
+void geneve_get_random_mac_addr(uint8_t *);
+void geneve_learn_fwd(int, struct mbuf *, struct ip *, struct ip6_hdr *, int);
+int geneve_need_fwd(struct ifnet *, struct mbuf *);
+int geneve_l2_fwd_local2tun(struct ifnet *, struct mbuf *, int);
+struct ifnet *get_geneve_ifp(uint32_t);
+struct ifnet *geneve_local_learn(struct ifnet *, struct mbuf *);
+struct if_dpdk_host_context *geneve_get_ctx_by_id(int);
+struct if_dpdk_host_context *geneve_get_ctx_by_sc(struct geneve_softc *);
 
-#endif /*  _NET_IF_GENEVE_H_ */
\ No newline at end of file
+#endif /*  _NET_IF_GENEVE_H_ */
Index: /branches/rel_apv_10_7/usr/src/sys/net/if_geneve.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/net/if_geneve.c	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/net/if_geneve.c	(working copy)
@@ -1,3 +1,12 @@
+/*------------------------------------------------------------------------------
+ * Copyright (C) 2025
+ * ArrayNetworks Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is not permitted unless authorized in writing by a duly
+ * appointed officer of ArrayNetworks Inc. or its derivatives
+ *--------------------------------------------------------------------------- */
+
 #include "opt_inet.h"
 #include "opt_inet6.h"
 
@@ -5,105 +14,3269 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
-#include <sys/eventhandler.h>
+#include <sys/queue.h>
 #include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/hash.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
 #include <sys/module.h>
-#include <sys/refcount.h>
-#include <sys/rmlock.h>
-#include <sys/priv.h>
-#include <sys/proc.h>
-#include <sys/queue.h>
-#include <sys/sbuf.h>
 #include <sys/socket.h>
-#include <sys/socketvar.h>
 #include <sys/sockio.h>
-#include <sys/sysctl.h>
-#include <sys/systm.h>
-
-#include <vm/uma.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/lock.h>
+#include <sys/rmlock.h>
+#include <sys/refcount.h>
 
 #include <net/bpf.h>
-#include <net/ethernet.h>
 #include <net/if.h>
-#include <net/if_var.h>
-#include <net/if_clone.h>
 #include <net/if_dl.h>
+#include <net/if_var.h>
 #include <net/if_types.h>
+#include <net/if_clone.h>
 #include <net/if_geneve.h>
-#include <net/netisr.h>
+#include <net/ethernet.h>
 
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/in_var.h>
-#include <netinet/in_pcb.h>
 #include <netinet/ip.h>
-#include <netinet/ip6.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
-#include <netinet/udp.h>
-#include <netinet/udp_var.h>
+#include <netinet/in_pcb.h>
 
-#include <click/app/proxy/proxy_errs.h>
 #include "kernelWrapper.h"
-#include <click/app/kernelapi/kernelapi.h>
-#include <click/sys/mbuf_atcp.h>
-#include <click/sys/clickaddr.h>
-#include <click/netinet/click_var.h>
-#include <click/app/util/generic_lock.h>
-#include <uinet_host_interface.h>
-#include <uinet_if_dpdk.h>
+#include "uinet_if_dpdk.h"
+#include "uinet_host_interface.h"
+#include "click/sys/clickaddr.h"
+#include "click/netinet/click_var.h"
+#include "click/app/kernelapi/kernelapi.h"
+
+/* Default maximum number of addresses in the forwarding table. */
+#ifndef GENEVE_FTABLE_MAX
+#define GENEVE_FTABLE_MAX     2000
+#endif
+
+/* Timeout (in seconds) of addresses learned in the forwarding table. */
+#ifndef GENEVE_FTABLE_TIMEOUT
+#define GENEVE_FTABLE_TIMEOUT (20 * 60)
+#endif
+
+/* Number of seconds between pruning attempts of the forwarding table. */
+#ifndef GENEVE_FTABLE_PRUNE
+#define GENEVE_FTABLE_PRUNE   (5 * 60)
+#endif
+
+#define GENEVE_SC_FTABLE_SHIFT           9
+#define GENEVE_SC_FTABLE_SIZE            (1 << GENEVE_SC_FTABLE_SHIFT)
+#define GENEVE_SC_FTABLE_MASK            (GENEVE_SC_FTABLE_SIZE - 1)
+#define GENEVE_SC_FTABLE_HASH(_sc, _mac) (geneve_mac_hash(_sc, _mac) % GENEVE_SC_FTABLE_SIZE)
+
+#define GENEVE_FTBL_WLOCK(_sc, i)    click_rwlock_write_lock(&((_sc)->geneve_ftbl_lock[i]))
+#define GENEVE_FTBL_WUNLOCK(_sc, i)  click_rwlock_write_unlock(&((_sc)->geneve_ftbl_lock[i]))
+#define GENEVE_FTBL_RLOCK(_sc, i)    click_rwlock_read_lock(&((_sc)->geneve_ftbl_lock[i]))
+#define GENEVE_FTBL_RUNLOCK(_sc, i)  click_rwlock_read_unlock(&((_sc)->geneve_ftbl_lock[i]))
+
+#define GENEVE_ACQUIRE(_sc)  refcount_acquire(&(_sc)->geneve_refcnt)
+#define GENEVE_RELEASE(_sc)  refcount_release(&(_sc)->geneve_refcnt)
+
+#define GENEVE_SO_VNI_HASH_SHIFT     6
+#define GENEVE_SO_VNI_HASH_SIZE      (1 << GENEVE_SO_VNI_HASH_SHIFT)
+#define GENEVE_SO_VNI_HASH(_vni)     ((_vni) % GENEVE_SO_VNI_HASH_SIZE)
+
+#define GENEVE_GTEP_RLOCK(gtep, _p)    rm_rlock(&gtep.gtep_lock, (_p))
+#define GENEVE_GTEP_RUNLOCK(gtep, _p)  rm_runlock(&gtep.gtep_lock, (_p))
+#define GENEVE_GTEP_WLOCK(gtep)        rm_wlock(&gtep.gtep_lock)
+#define GENEVE_GTEP_WUNLOCK(gtep)      rm_wunlock(&gtep.gtep_lock)
+#define GENEVE_GTEP_LOCK_ASSERT(gtep)  rm_assert(&gtep.gtep_lock, RA_LOCKED)
+#define GENEVE_GTEP_LOCK_WASSERT(gtep) rm_assert(&gtep.gtep_lock, RA_WLOCKED)
+
+#define GENEVE_FE_FLAG_DYNAMIC       0x01
+#define GENEVE_FE_FLAG_STATIC        0x02
+#define GENEVE_FE_FLAG_LOCAL         0x04
+#define GENEVE_FE_FLAG_REMOTE        0x08
+#define GENEVE_FE_IS_DYNAMIC(_fe)    ((_fe)->flags & GENEVE_FE_FLAG_DYNAMIC)
+
+#define GENEVE_TUN_ACQUIRE(_tun)     refcount_acquire(&(_tun)->refcnt)
+#define GENEVE_TUN_RELEASE(_tun)     refcount_release(&(_tun)->refcnt)
+
+struct geneve_stat {
+    uint32_t  geneve_tun_learn;
+    uint32_t  geneve_local_learn;
+    uint32_t  geneve_not_tun_ip;
+    uint32_t  geneve_tun_pkt_in;
+    uint32_t  geneve_tun_pkt_out;
+    uint32_t  geneve_tun_pkt_fwd;
+    uint32_t  geneve_tun_pkt_flood;
+    uint32_t  geneve_local_pkt_in;
+    uint32_t  geneve_local_pkt_out;
+    uint32_t  geneve_local_pkt_fwd;
+    uint32_t  geneve_local_pkt_flood;
+    uint32_t  geneve_ftable_nospace;
+    uint32_t  geneve_ftable_alloc_fail;
+    uint32_t  geneve_ftable_insert_fail;
+};
+
+struct geneve_softc {
+    struct ifnet                *geneve_ifp;
+    struct if_dpdk_host_context *dpdk_host_ctx;
+
+    uint32_t                    geneve_vni;
+    uint8_t                     geneve_ttl;
+    uint32_t                    geneve_unit;
+    uint32_t                    geneve_flags;
+    uint16_t                    geneve_min_port;
+    uint16_t                    geneve_max_port;
+    uint32_t                    geneve_port_hash_key;
+#define GENEVE_FLAG_INIT        0x0001
+#define GENEVE_FLAG_TEARDOWN    0x0002
+#define GENEVE_FLAG_LEARN       0x0004
+
+    /* Lookup table from MAC address to forwarding entry. */
+    uint32_t                    geneve_ftable_cnt;
+    uint32_t                    geneve_ftable_max;
+    uint32_t                    geneve_ftable_timeout;
+    uint32_t                    geneve_ftable_hash_key;
+    struct geneve_ftable_head   *geneve_ftable;
+    click_rwlock_t              *geneve_ftbl_lock;  /*ftable lock for each hash index*/
+
+    union geneve_sockaddr       geneve_src_addr;
+    union geneve_sockaddr       geneve_dst_addr;
+    uint8_t                     geneve_hwaddr[ETHER_ADDR_LEN];
+
+    struct ifnet                *geneve_gw_ifp;     /* geneve gw local bound interface */
+
+    struct geneve_tunnel        *geneve_tunl_tbl[GENEVE_VNI_MAX_TUNNEL];
+
+    struct callout              geneve_callout;
+
+    LIST_ENTRY(geneve_softc)    geneve_entry;
+    LIST_ENTRY(geneve_softc)    geneve_ifdetach_list;
+    LIST_ENTRY(geneve_softc)    geneve_list_entry;
+
+    volatile u_int              geneve_refcnt;
+
+    struct mtx                  geneve_mtx;
+    struct rmlock               geneve_lock;
+
+    struct geneve_stat          geneve_stat;
+};
+
+struct geneve_control {
+    int (*c_func)(struct geneve_softc *, void *);
+    int c_argsize;
+    int c_flags;
+#define GENEVE_CTRL_FLAG_COPYIN  0x01
+#define GENEVE_CTRL_FLAG_COPYOUT 0x02
+#define GENEVE_CTRL_FLAG_SUSER   0x04
+};
+
+struct geneve_tunnel;
+LIST_HEAD(geneve_tunnel_head, geneve_tunnel);
+LIST_HEAD(geneve_ftable_head, geneve_ftable_entry);
+
+struct geneve_tunnel {
+    char                      name[MAX_TUNNEL_NAME_LEN];
+    u_int                     refcnt;
+    struct rmlock             lock;
+    int                       isipv6;
+    union geneve_sockaddr     src_addr;
+    union geneve_sockaddr     dst_addr;
+    struct socket             *sock;
+    struct ifnet              *ifp;
+    struct ip_moptions        *im4o;
+    struct ip6_moptions       *im6o;
+    LIST_ENTRY(geneve_tunnel) entries;
+};
+
+struct geneve_gtep {
+    uint16_t                  geneve_port;
+    struct rmlock             gtep_lock;
+    int                       vni_num;
+    int                       tunnel_num;
+    struct geneve_tunnel_head tunnel_list;
+    struct geneve_softc_head  vni_hash[GENEVE_SO_VNI_HASH_SIZE];
+};
+
+struct geneve_ftable_entry {
+    LIST_ENTRY(geneve_ftable_entry) hash;
+    uint16_t                        flags;
+    uint8_t                         mac[ETHER_ADDR_LEN];
+    union geneve_sockaddr           raddr;
+    struct geneve_tunnel            *tunnel;    /* Tunnel, used as outter IP src */
+    struct ifnet                    *ifp_local; /* currently not used: sc has the associated interface */
+    time_t                          expire;
+};
+
+/* geneve global vars */
+extern int geneve_port;
+extern int geneve_enable;
+static int gtep_inited = 0;
+static struct geneve_gtep gtep;
+struct geneve_softc_head geneve_sc_list = LIST_HEAD_INITIALIZER(geneve_sc_list);
+struct geneve_softc *geneve_softc_arr[MAX_GENEVE] = {NULL};
+static uma_zone_t geneve_ftable_entry_zone;
+
+static const char geneve_name[] = "geneve";
+static MALLOC_DEFINE(M_GENEVE, geneve_name, "Generic Network Virtualization Encapsulation Interface");
+static struct if_clone *geneve_cloner;
+static int geneve_ftable_prune_period = GENEVE_FTABLE_PRUNE;
+
+/*default geneve mode is p2mp*/
+int geneve_mode = GNV_P2MP;
+SYSCTL_INT(_net_inet_clicktcp, OID_AUTO, geneve_mode, CTLFLAG_RW, &geneve_mode, 0, "geneve mode");
+
+int geneve_learn = GENEVE_LEARN_ON;
+SYSCTL_INT(_net_inet_clicktcp, OID_AUTO, geneve_learn, CTLFLAG_RW, &geneve_learn, 0, "geneve learn");
+
+int geneve_debug = GENEVE_DBG_OFF;
+SYSCTL_INT(_net_inet_clicktcp, OID_AUTO, geneve_debug, CTLFLAG_RW, &geneve_debug, 0, "geneve debug");
+
+static uint16_t geneve_pick_source_port(struct geneve_softc *, struct mbuf *);
+static void geneve_encap_header(struct geneve_softc *, struct geneve_tunnel *, struct mbuf *, int, uint16_t, uint16_t, int);
+static int geneve_encap4_send(struct geneve_softc *, struct geneve_tunnel *, const union geneve_sockaddr *, struct mbuf *, int);
+static int geneve_encap6_send(struct geneve_softc *, struct geneve_tunnel *, const union geneve_sockaddr *, struct mbuf *, int);
+
+static int  geneve_clone_create(struct if_clone *, int, caddr_t);
+static void geneve_clone_destroy(struct ifnet *);
+
+static void geneve_init(void *);
+static void geneve_init_complete(struct geneve_softc *);
+static void geneve_teardown_wait(struct geneve_softc *);
+static void geneve_teardown_complete(struct geneve_softc *);
+static void geneve_teardown_locked(struct geneve_softc *);
+static void geneve_teardown(struct geneve_softc *);
+static void geneve_release(struct geneve_softc *);
+
+static int  geneve_ioctl(struct ifnet *, u_long, caddr_t);
+static int  geneve_ioctl_drvspec(struct geneve_softc *, struct ifdrv *, int);
+static int  geneve_ioctl_ifflags(struct geneve_softc *);
+
+static int  geneve_set_promisc(struct ifnet *, int);
+static int  geneve_check_vni(uint32_t vni);
+static int  geneve_ctrl_set_vni(struct geneve_softc *, void *);
+
+static void gtep_init(void);
+static void geneve_timer(void *xsc);
+static void geneve_fakeaddr(struct geneve_softc *);
+static void geneve_set_default_config(struct geneve_softc *);
+static void geneve_qflush(struct ifnet *ifp __unused);
+static int  geneve_create_ctx(struct geneve_softc *, int);
+static void geneve_delete_ctx(int port_id);
+static int  geneve_transmit(struct ifnet *, struct mbuf *);
+static int  atcp_geneve_output(struct ifnet *, struct mbuf *);
+
+static int  geneve_join(struct geneve_tunnel *, union geneve_sockaddr *, union geneve_sockaddr *);
+static void geneve_leave(struct geneve_tunnel *, union geneve_sockaddr *, union geneve_sockaddr *);
+
+static struct geneve_tunnel *find_geneve_tunnel_by_ip(struct geneve_softc *, const struct sockaddr *, const struct sockaddr *);
+static struct geneve_tunnel *check_geneve_ip_on_tunnel(struct geneve_softc *, const struct sockaddr *, const struct sockaddr *, int);
+
+static int  geneve_sockaddr_cmp(const union geneve_sockaddr *, const struct sockaddr *);
+static void geneve_sockaddr_copy(union geneve_sockaddr *, const struct sockaddr *);
+static int  geneve_sockaddr_in_equal(const union geneve_sockaddr *, const struct sockaddr *);
+static void geneve_sockaddr_in_copy(union geneve_sockaddr *, const struct sockaddr *);
+static int  geneve_sockaddr_supported(const union geneve_sockaddr *, int);
+static int  geneve_sockaddr_in_any(const union geneve_sockaddr *);
+static int  geneve_sockaddr_in_multicast(const union geneve_sockaddr *);
+
+static void geneve_ftable_init(struct geneve_softc *);
+static void geneve_ftable_fini(struct geneve_softc *);
+static void geneve_ftable_flush(struct geneve_softc *, int, struct geneve_tunnel *);
+static int  geneve_ftable_has_tunnel(struct geneve_softc *, struct geneve_tunnel *);
+static void geneve_ftable_entry_init(struct geneve_softc *, struct geneve_ftable_entry *,
+                                    const uint8_t *, const struct sockaddr *, uint32_t);
+static void geneve_ftable_entry_destroy(struct geneve_softc *, struct geneve_ftable_entry *);
+static __inline struct geneve_ftable_entry *geneve_ftable_entry_alloc(void);
+static __inline void geneve_ftable_entry_free(struct geneve_ftable_entry *);
+static int geneve_ftable_addr_cmp(const uint8_t *, const uint8_t *);
+static int geneve_ftable_entry_insert(struct geneve_softc *, struct geneve_ftable_entry *);
+static struct geneve_ftable_entry *geneve_ftable_entry_lookup(struct geneve_softc *, const uint8_t *);
+static void geneve_ftable_entry_dump(struct geneve_ftable_entry *, struct sbuf *);
+static int  geneve_ftable_update_locked(struct geneve_softc *, const struct sockaddr *, struct geneve_tunnel *, const uint8_t *,
+                                        struct rm_priotracker *, uint32_t flags);
+static int  geneve_ftable_update(struct geneve_softc *, const struct sockaddr *, struct geneve_tunnel *, const uint8_t *, uint32_t);
+
+static void geneve_l2_forward_tun2local(struct ifnet *, struct mbuf *);
+
+static struct geneve_softc* geneve_lookup_softc(uint32_t);
+static struct geneve_softc *geneve_lookup_softc_locked(uint32_t);
+static int  geneve_insert_softc(struct geneve_softc *);
+static void geneve_remove_softc(struct geneve_softc *);
+
+static void	geneve_load(void);
+static void	geneve_unload(void);
+static int	geneve_modevent(module_t, int, void *);
+
+void *if_dpdk_create_geneve_ctx(char *, int);
+extern cafw_ifnode_t *cafw_ifnode_new(uint16_t);
+extern int vlan_setflags(struct ifnet *, int);
+
+static const struct geneve_control geneve_control_table[] = {
+    [GENEVE_CMD_SET_VNI] =
+        {
+            geneve_ctrl_set_vni, sizeof(struct ifgenevecmd), GENEVE_CTRL_FLAG_COPYIN | GENEVE_CTRL_FLAG_SUSER,
+        },
+
+    // [GENEVE_CMD_SET_LEARN] =
+    //     {
+    //         geneve_ctrl_set_learn, sizeof(struct ifgenevecmd), GENEVE_CTRL_FLAG_COPYIN | GENEVE_CTRL_FLAG_SUSER,
+    //     },
+
+    // [GENEVE_CMD_FTABLE_ENTRY_ADD] =
+    //     {
+    //         geneve_ctrl_ftable_entry_add, sizeof(struct ifgenevecmd), GENEVE_CTRL_FLAG_COPYIN | GENEVE_CTRL_FLAG_SUSER,
+    //     },
+
+    // [GENEVE_CMD_FTABLE_ENTRY_REM] =
+    //     {
+    //         geneve_ctrl_ftable_entry_rem, sizeof(struct ifgenevecmd), GENEVE_CTRL_FLAG_COPYIN | GENEVE_CTRL_FLAG_SUSER,
+    //     },
+};
+
+static const int geneve_control_table_size = nitems(geneve_control_table);
+
+struct if_dpdk_host_context *
+geneve_get_ctx_by_id(int port_id)
+{
+    GENEVE_DBG_ENTER("port_id: %d", port_id);
+
+    if (geneve_softc_arr[port_id]) {
+        return geneve_softc_arr[port_id]->dpdk_host_ctx;
+    }
+
+    return NULL;
+}
+
+struct if_dpdk_host_context *
+geneve_get_ctx_by_sc(struct geneve_softc *sc)
+{
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+
+    if (sc) {
+        return sc->dpdk_host_ctx;
+    }
+
+    return NULL;
+}
+
+struct ifnet *
+get_geneve_ifp(uint32_t vni)
+{
+    struct geneve_softc *sc = NULL;
+
+    GENEVE_DBG_ENTER("vni: %d", vni);
+
+    sc = geneve_lookup_softc(vni);
+    if (!sc) {
+        return NULL;
+    }
+    
+    return sc->geneve_ifp;
+}
 
-ca_errcode_t geneve_port_func(void* pcb, uint16_t vxl_port) {
-	app_printf(pcb, "GENEVE port: %d\n", vxl_port);
+int 
+geneve_set_promisc(struct ifnet *ifp, int flag)
+{
+    int ret;
+
+    GENEVE_DBG_ENTER("ifp: %p, if_name: %s, flag: %d", ifp, ifp->if_xname, flag);
+
+    /*Currently can only handle vlan parent is physical port situation*/
+    if (flag) {
+        ret = vlan_setflags(ifp, 1);
+    } else {
+        ret = vlan_setflags(ifp, 0);
+    }
+
+    return ret;
+}
+
+int 
+get_geneve_mac(void *pcb, uint32_t unit, void **mac, int32_t *length) 
+{
+    struct geneve_softc *sc = NULL;
+    uint8_t *buf = NULL;
+    
+    GENEVE_DBG_ENTER("pcb: %p, unit: %u, mac: %p, length: %d", pcb, unit, mac, *length);
+
+    buf = (uint8_t *)malloc(ETHER_ADDR_LEN, M_TEMP, M_NOWAIT|M_ZERO);
+    if (!buf) {
+        GENEVE_DBG_ERR("set geneve mac error.");
+        return -1;
+    }
+    
+    LIST_FOREACH(sc, &geneve_sc_list, geneve_list_entry) {
+        if (sc->geneve_unit == unit) {     
+            memcpy(buf, sc->geneve_hwaddr, ETHER_ADDR_LEN);
+            break;
+        }
+    }
+
+    *mac = buf;
+    *length = ETHER_ADDR_LEN;   
+
+    return 0;
+}
+
+int
+geneve_enable_func(void *pcb)
+{
+    GENEVE_DBG_ENTER("pcb: %p", pcb);
+    geneve_enable = GENEVE_ENABLE;
+    return 0;
+}
+
+int
+geneve_disable_func(void *pcb)
+{
+    GENEVE_DBG_ENTER("pcb: %p", pcb);
+    geneve_enable = GENEVE_DISABLE;
+    return 0;
+}
+
+int
+geneve_port_func(void *pcb, uint16_t port)
+{
+    GENEVE_DBG_ENTER("pcb: %p, port: %u", pcb, port);
+    geneve_port = port;
+    return 0;
+}
+
+int
+geneve_learn_func(void *pcb, char *learn_str)
+{
+    GENEVE_DBG_ENTER("pcb: %p, learn_str: %s", pcb, learn_str);
+
+    if (!strcmp(learn_str, "on")) {
+        geneve_learn = GENEVE_LEARN_ON;
+    } else if (!strcmp(learn_str, "off")) {
+        geneve_learn = GENEVE_LEARN_OFF;
+    } else {
+        GENEVE_DBG_ERR("The supported values are on or off.");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int geneve_str2mac(char *mac, char *str)
+{
+	unsigned int macf[6];
+	int i;
+
+	if (sscanf(str, "%x:%x:%x:%x:%x:%x",
+		   &macf[0], &macf[1], &macf[2],
+		   &macf[3], &macf[4], &macf[5]) != 6)
+		return -1;
+
+	for (i = 0; i < 6; i++)
+		*mac++ = (uint8_t) macf[i];
+	
 	return 0;
 }
 
-ca_errcode_t geneve_enable_func(void* pcb) {
-	app_printf(pcb, "GENEVE enable.\n");
+static char* geneve_mac2str(unsigned char* mac) 
+{
+        static char mac_str[6*3];
+
+        sprintf(mac_str, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
+                mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+        return mac_str;
+}
+
+int 
+geneve_forwarding_remote_add(void *pcb, uint32_t vni, char *mac, char *gtep_ip) {
+    uint8_t gnv_mac[ETHER_ADDR_LEN];
+	struct geneve_softc* sc;
+	int ret, i;
+	union geneve_sockaddr gtep_addr;
+	struct in_addr gtep_r;
+	struct in6_addr gtep_r6;
+	int isipv6;
+	struct geneve_tunnel* tun = NULL;
+	struct ether_addr ea;
+	struct ether_addr dummy;
+
+	sc = geneve_lookup_softc(vni);
+	if (NULL == sc) {
+		app_printf(pcb, "GENEVE interface does not exist.\n");
+		return -1;
+	}
+
+	ret = geneve_str2mac(gnv_mac, mac);
+	if (ret) {
+		app_printf(pcb, "Incorrect remote MAC address format\n");
+		return -1;
+	}
+
+	if (!ether_aton_r(mac, &ea)) {
+		app_printf(pcb, "Illegal MAC address\n");
+		return -1;
+	} else {
+		bzero(&dummy, sizeof(dummy));
+		if (ea.octet[0] & 0x01 || !memcmp(&dummy, &ea, sizeof(dummy))) {
+			app_printf(pcb,"Invalid MAC address %s.\n", mac);
+			return -1;
+		}
+	}
+
+	/*ip processing*/
+	if(strstr(gtep_ip, ".") != NULL) {
+		isipv6 = 0;
+		ret = inet_aton (gtep_ip, &gtep_r);
+		if (1 != ret) {
+			app_printf(pcb, "Incorrect IP format.\n");
+			return -7;
+		}
+	} else {
+		isipv6 = 1;
+		ret = inet_pton(AF_INET6, gtep_ip, &gtep_r6);
+		if (1 != ret) {
+			app_printf(pcb, "Incorrect IP format\n");
+			return -7;
+		}
+	}
+
+	if (isipv6) {
+		gtep_addr.in6.sin6_family = AF_INET6;
+		gtep_addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+		gtep_addr.in6.sin6_addr = gtep_r6;
+	} else {
+		gtep_addr.in4.sin_family = AF_INET;
+		gtep_addr.in4.sin_len = sizeof(struct sockaddr_in);
+		gtep_addr.in4.sin_addr.s_addr = gtep_r.s_addr;
+	}
+
+	/*get local vtep ip*/
+	if (GNV_MCAST == geneve_mode) {
+		tun = sc->geneve_tunl_tbl[0];
+	} else {
+		for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; ++i) {
+			tun = sc->geneve_tunl_tbl[i];
+			if (NULL != tun) {
+				if (isipv6) {
+					if (IN6_ARE_ADDR_EQUAL(&gtep_r6, &tun->dst_addr.in6.sin6_addr)) {
+						break;
+					}
+				} else {
+					if (gtep_r.s_addr == tun->dst_addr.in4.sin_addr.s_addr) {
+						break;
+					}
+				}
+			}
+		}	
+	}
+
+	if (tun == NULL) {
+		app_printf(pcb, "The remote GTEP IP address does not belong to any tunnel.\n");
+		return -1;
+	}
+
+	ret = geneve_ftable_update(sc, &gtep_addr.sa, tun, gnv_mac, (GENEVE_FE_FLAG_STATIC | GENEVE_FE_FLAG_REMOTE));
+	if (ret) {
+		app_printf(pcb, "Failed to add a forwarding entry to the to the GTEP forwarding table.\n");
+		return -1;
+	}
+
 	return 0;
 }
 
-ca_errcode_t geneve_disable_func(void* pcb) {
-	app_printf(pcb, "GENEVE disable.\n");
+int 
+geneve_forwarding_remote_del(void *pcb, uint32_t vni, char *mac)  {
+    uint8_t gnv_mac[ETHER_ADDR_LEN];
+	struct geneve_softc* sc;
+	int ret;
+	struct geneve_ftable_entry* fe;
+
+	sc = geneve_lookup_softc(vni);
+	if (NULL == sc) {
+		app_printf(pcb, "GENEVE interface does not exist.\n");
+		return -1;
+	}
+
+	ret = geneve_str2mac(gnv_mac, mac);
+	if (ret) {
+		app_printf(pcb, "Incorrect remote MAC address format.\n");
+		return -1;
+	}
+
+	fe = geneve_ftable_entry_lookup(sc, gnv_mac);
+	if (NULL == fe) {
+		app_printf(pcb, "The forwarding entry does not exist.\n");
+		return -1;
+	}
+
+	if (fe->flags != (GENEVE_FE_FLAG_REMOTE | GENEVE_FE_FLAG_STATIC)) {
+		app_printf(pcb, "This is not a manually configured forwarding entry.\n");
+		return -1;
+	}
+
+	geneve_ftable_entry_destroy(sc, fe);
 	return 0;
 }
 
-ca_errcode_t geneve_learn_func(void* pcb, char* learn_str) {
-	app_printf(pcb, "GENEVE learn %s.\n", learn_str);
+int 
+geneve_forwarding_local_add(void *pcb, uint32_t vni, char *mac) {
+    uint8_t gnv_mac[ETHER_ADDR_LEN];
+	struct geneve_softc* sc;
+	int ret;
+
+	sc = geneve_lookup_softc(vni);
+	if (NULL == sc) {
+		app_printf(pcb, "GENEVE interface does not exist.\n");
+		return -1;
+	}
+
+	ret = geneve_str2mac(gnv_mac, mac);
+	if (ret) {
+		app_printf(pcb, "Incorrect remote MAC address format.\n");
+		return -1;
+	}
+
+	/*Need geneve associate first before configure local forwarding entry*/
+	if (NULL == sc->geneve_gw_ifp) {
+		app_printf(pcb, "Please associate GENEVE interface with VLAN interface first.\n");
+		return -1;
+	}
+
+	ret = geneve_ftable_update(sc, NULL, NULL, gnv_mac, (GENEVE_FE_FLAG_LOCAL | GENEVE_FE_FLAG_STATIC));
+	if (ret) {
+		app_printf(pcb, "Failed to add a a forwarding entry to the GENEVE-VLAN forwarding table\n");
+		return -1;
+	}
+
 	return 0;
 }
 
-int geneve_forwarding_remote_add(void* pcb, uint32_t vni, char* mac, char* vtep_ip) {
-	app_printf(pcb, "GENEVE forward remote add vni: %d, mac: %s, dstip: %s\n", vni, mac, vtep_ip);
+int 
+geneve_forwarding_local_del(void *pcb, uint32_t vni, char *mac)  {
+    uint8_t gnv_mac[ETHER_ADDR_LEN];
+	struct geneve_softc* sc;
+	int ret;
+	struct geneve_ftable_entry* fe;
+	
+	sc = geneve_lookup_softc(vni);
+	if (NULL == sc) {
+		app_printf(pcb, "GENEVE interface does not exist.\n");
+		return -1;
+	}
+	
+	ret = geneve_str2mac(gnv_mac, mac);
+	if (ret) {
+		app_printf(pcb, "Incorrect remote MAC address format.\n");
+		return -1;
+	}
+	
+	fe = geneve_ftable_entry_lookup(sc, gnv_mac);
+	if (NULL == fe) {
+		app_printf(pcb, "The forwarding entry does not exist.\n");
+		return -1;
+	}
+	
+	if (fe->flags != (GENEVE_FE_FLAG_LOCAL | GENEVE_FE_FLAG_STATIC)) {
+		app_printf(pcb, "This is not a manually configured forwarding entry.\n");
+		return -1;
+	}
+	
+	geneve_ftable_entry_destroy(sc, fe);
 	return 0;
 }
 
-int geneve_forwarding_remote_del(void* pcb, uint32_t vni, char* mac)  {
-	app_printf(pcb, "GENEVE forward remote del vni: %d, mac: %s\n", vni, mac);
+int 
+clear_geneve_forwarding_static(void *pcb, uint32_t vni) {
+    struct geneve_softc* sc;
+	int i;
+	struct geneve_ftable_entry* fe, *tfe;
+
+	sc = geneve_lookup_softc(vni);
+	if (NULL == sc) {
+		app_printf(pcb, "GENEVE interface does not exist\n");
+		return -1;
+	}
+	
+	for (i = 0; i < GENEVE_SC_FTABLE_SIZE; ++i) {
+		GENEVE_FTBL_WLOCK(sc, i);
+		
+		LIST_FOREACH_SAFE(fe, &sc->geneve_ftable[i], hash, tfe) {
+			if (!GENEVE_FE_IS_DYNAMIC(fe)) {
+				geneve_ftable_entry_destroy(sc, fe);
+			}
+		}
+
+		GENEVE_FTBL_WUNLOCK(sc, i);
+	}
+
 	return 0;
 }
 
-int geneve_forwarding_local_add(void* pcb, uint32_t vni, char* mac) {
-	app_printf(pcb, "GENEVE forward local add vni: %d, mac: %s\n", vni, mac);
+int 
+clear_geneve_forwarding_dynamic(void *pcb, uint32_t vni) {
+    struct geneve_softc* sc;
+	int i;
+	struct geneve_ftable_entry* fe, *tfe;
+
+	sc = geneve_lookup_softc(vni);
+	if (NULL == sc) {
+		app_printf(pcb, "GENEVE does not exist.\n");
+		return -1;
+	}
+	
+	for (i = 0; i < GENEVE_SC_FTABLE_SIZE; ++i) {
+		GENEVE_FTBL_WLOCK(sc, i);
+		
+		LIST_FOREACH_SAFE(fe, &sc->geneve_ftable[i], hash, tfe) {
+			if (GENEVE_FE_IS_DYNAMIC(fe)) {
+				geneve_ftable_entry_destroy(sc, fe);
+			}
+		}
+
+		GENEVE_FTBL_WUNLOCK(sc, i);
+	}
+
 	return 0;
 }
 
-int geneve_forwarding_local_del(void* pcb, uint32_t vni, char* mac)  {
-	app_printf(pcb, "GENEVE forward local del vni: %d, dstmac: %s\n", vni, mac);
+int show_geneve_forwarding_kern(void* pcb, uint32_t vni, char* mac, char* local_port_name)
+{
+	struct geneve_softc* sc;
+	struct geneve_ftable_entry* fe, *tfe;
+	uint8_t gnv_mac[ETHER_ADDR_LEN];
+	int i, ret, flags = 0;
+	struct ifnet* gtep_vlan;
+	char ip_str[INET6_ADDRSTRLEN];
+
+	sc = geneve_lookup_softc(vni);
+	if (NULL == sc) {
+		app_printf(pcb, "GENEVE does not exist.\n");
+		return -1;
+	}
+	
+	if (NULL == mac || mac[0] == '\0') {
+		app_printf(pcb, "\nRemote forwarding entries: (to GTEP)\n ========================================\n");
+		app_printf(pcb, "     MAC               GTEP-IP            TYPE\n");
+		/*need acquire lock?? seems not*/
+		for (i = 0; i < GENEVE_SC_FTABLE_SIZE; ++i) {
+			GENEVE_FTBL_RLOCK(sc, i);
+			LIST_FOREACH_SAFE(fe, &sc->geneve_ftable[i], hash, tfe) {
+				flags = 0;
+				if (fe->flags & GENEVE_FE_FLAG_REMOTE) {
+					if (fe->flags & GENEVE_FE_FLAG_DYNAMIC) {
+						flags = 1;
+					}
+					if (GENEVE_SOCKADDR_IS_IPV6(&fe->raddr)) {
+						inet_ntop(AF_INET6, &fe->raddr.in6.sin6_addr, ip_str, sizeof(ip_str));
+					} else {
+						inet_ntop(AF_INET, &fe->raddr.in4.sin_addr, ip_str, sizeof(ip_str));
+					}
+					app_printf(pcb, "%s       %s          %s\n", geneve_mac2str(fe->mac), ip_str, flags?"Dynamic":"Static");
+				}
+			}
+			GENEVE_FTBL_RUNLOCK(sc, i);
+		}
+		gtep_vlan = sc->geneve_gw_ifp;
+		if (NULL == gtep_vlan || local_port_name[0] == '\0') {
+			return 0;
+		}
+		app_printf(pcb, "\nLocal forwarding entries: (to L2 interface)\n ========================================\n");
+		app_printf(pcb, "     MAC                 VLAN              TYPE\n");
+		
+		/*need acquire lock?? seems not*/
+		for (i = 0; i < GENEVE_SC_FTABLE_SIZE; ++i) {
+			GENEVE_FTBL_RLOCK(sc, i);
+			LIST_FOREACH_SAFE(fe, &sc->geneve_ftable[i], hash, tfe) {
+				flags = 0;
+				if (fe->flags & GENEVE_FE_FLAG_LOCAL) {
+					if (fe->flags & GENEVE_FE_FLAG_DYNAMIC) {
+						flags = 1;
+					}
+					app_printf(pcb, "%s          %s           %s\n", geneve_mac2str(fe->mac), local_port_name, flags?"Dynamic":"Static");
+				}
+			}
+			GENEVE_FTBL_RUNLOCK(sc, i);
+		}
+	} else {
+		ret = geneve_str2mac(gnv_mac, mac);
+		if (ret) {
+			app_printf(pcb, "Please type in correct mac address.\n");
+			return -1;
+		}
+		
+		fe = geneve_ftable_entry_lookup(sc, gnv_mac);
+		if (NULL == fe) {
+			app_printf(pcb, "This forwarding entry does not exist.\n");
+			return -1;
+		}
+
+		gtep_vlan = sc->geneve_gw_ifp;
+
+		if (fe->flags & GENEVE_FE_FLAG_LOCAL) {
+			if (NULL == gtep_vlan) { /*Need destroy this entry??*/
+				return -1;
+			}
+			app_printf(pcb, "        MAC                 VLAN              TYPE\n");
+			flags = 0;
+			if (fe->flags & GENEVE_FE_FLAG_DYNAMIC) {
+				flags = 1;
+			}
+			app_printf(pcb, "%s       %s          %s\n", geneve_mac2str(fe->mac), gtep_vlan->if_xname, flags?"Dynamic":"Static");
+		} else {
+			app_printf(pcb, "        MAC               VTEP-IP         TYPE\n");
+			flags = 0;
+			if (fe->flags & GENEVE_FE_FLAG_DYNAMIC) {
+				flags = 1;
+			}
+			if (GENEVE_SOCKADDR_IS_IPV6(&fe->raddr)) {
+				inet_ntop(AF_INET6, &fe->raddr.in6.sin6_addr, ip_str, sizeof(ip_str));
+			} else {
+				inet_ntop(AF_INET, &fe->raddr.in4.sin_addr, ip_str, sizeof(ip_str));
+			}
+			app_printf(pcb, "%s       %s          %s\n", geneve_mac2str(fe->mac), ip_str, flags?"Dynamic":"Static");
+		}
+	}
 	return 0;
 }
 
+int write_geneve_forwarding_kern(void* pcb, void** config_data, int* length)
+{
+	char* buffer = NULL;
+	char* cur = NULL;
+	int i, j;
+	int config_len = 0;
+	struct geneve_softc* sc;
+	struct in_addr gtep_ip;
+	struct geneve_ftable_entry* fe, *tfe;
+	struct ifnet* gtep_vlan;
+
+	/*calculate config len: temp value here*/
+	config_len = sizeof(struct geneve_softc) * 1000;
+
+	MALLOC(buffer, char *, config_len, M_TEMP, M_NOWAIT);
+
+	if (buffer == NULL) {
+		app_printf(pcb, "Out of memory for buffer size %d(%p)\n", config_len, buffer);
+		return 0;
+	}
+	bzero(buffer, config_len);
+
+	*config_data = buffer;
+	cur = buffer;
+
+	for (i = 0; i < GENEVE_SO_VNI_HASH_SIZE; ++i) {
+		LIST_FOREACH(sc, &gtep.vni_hash[i], geneve_entry) {
+			for (j = 0; j < GENEVE_SC_FTABLE_SIZE; ++j) {
+				GENEVE_FTBL_RLOCK(sc, j);
+				LIST_FOREACH_SAFE(fe, &sc->geneve_ftable[j], hash, tfe) {
+					if (!GENEVE_FE_IS_DYNAMIC(fe)) {
+						if (fe->flags & GENEVE_FE_FLAG_REMOTE) {
+							gtep_ip.s_addr = fe->raddr.in4.sin_addr.s_addr;
+							cur += sprintf(cur, "geneve forwarding remote %d %s %s\n", sc->geneve_vni, geneve_mac2str(fe->mac), inet_ntoa(gtep_ip));
+						} else {
+							gtep_vlan = sc->geneve_gw_ifp;
+							if (NULL != gtep_vlan) {
+								cur += sprintf(cur, "geneve forwarding local %d %s\n", sc->geneve_vni, geneve_mac2str(fe->mac));
+							}
+						}
+						
+					}
+				}
+				GENEVE_FTBL_RUNLOCK(sc, j);
+			}
+		}
+		/*sleep(1);*/
+	}
+
+	*length = cur - buffer + 1;
 
-int clear_geneve_forwarding_static(void* pcb, uint32_t vni) {
-	app_printf(pcb, "Clear GENEVE forward static vni: %d\n", vni);
 	return 0;
 }
 
-int clear_geneve_forwarding_dynamic(void* pcb, uint32_t vni) {
-	app_printf(pcb, "Clear GENEVE forward dynamic vni: %d\n", vni);
+int clear_geneve_forwarding_kern(void* pcb, uint32_t vni)
+{
+	int ret;
+	ret = clear_geneve_forwarding_dynamic(pcb, vni);
+	if (ret) {
+		return ret;
+	}
+	ret = clear_geneve_forwarding_static(pcb, vni);
+
+	return ret;
+}
+
+int 
+clear_geneve_environ_kern(void *pcb) 
+{
+    GENEVE_DBG_ENTER("pcb: %p", pcb);
+    geneve_enable = GENEVE_DISABLE;
+    geneve_port = GENEVE_DEFAULT_PORT;
+    geneve_learn = GENEVE_LEARN_ON;
+    return 0;
+}
+
+int 
+geneve_associate_kern(void* pcb, char *geneve_intf, char *vlan_intf)
+{
+    struct ifnet *geneve_ifp, *vlan_ifp, *vlan_parent;
+    struct geneve_softc* sc;
+    int ret;
+
+    GENEVE_DBG_ENTER("pcb: %p, geneve_intf: %s, vlan_intf: %s", pcb, geneve_intf, vlan_intf);
+
+    geneve_ifp = ifunit(geneve_intf);
+    vlan_ifp = ifunit(vlan_intf);
+
+    if (!geneve_ifp || !vlan_ifp) {
+        GENEVE_DBG_ERR("The GENEVE or VLAN interface does not exist.");
+        return -1;
+    }
+
+    vlan_parent = get_vlan_parent(vlan_ifp);
+
+    sc = geneve_ifp->if_softc;
+    if (sc->geneve_gw_ifp) {
+        GENEVE_DBG_ERR("The GENEVE interface has been associated with other VLAN interface.");
+        return -1;
+    } else if (vlan_ifp->if_flags & IFF_GENEVE_BIND || vlan_ifp->geneve_vni != 0) {
+        GENEVE_DBG_ERR("The VNI number %d has been used.", vlan_ifp->geneve_vni);
+        return -1;
+    }
+    
+    sc->geneve_gw_ifp = vlan_ifp;
+    vlan_ifp->if_flags |= (IFF_UP | IFF_GENEVE_BIND | IFF_PROMISC | IFF_PPROMISC | IFF_ALLMULTI);
+    vlan_parent->if_flags |= IFF_ALLMULTI;
+    vlan_ifp->geneve_vni = sc->geneve_vni;
+
+    ret = geneve_set_promisc(vlan_ifp, 1);
+    if (ret == 0) {
+        vlan_parent->if_flags |= IFF_PPROMISC;
+    }
+
+    return ret;
+}
+
+int no_geneve_associate_kern(void* pcb, char* gnv_intf, char* vlan_intf)
+{
+	struct ifnet *gnv_ifp, *vlan_ifp, *vlan_parent;
+	struct geneve_softc* sc;
+	int ret;
+
+	gnv_ifp = ifunit(gnv_intf);
+	vlan_ifp = ifunit(vlan_intf);
+
+	if (NULL == gnv_ifp || NULL == vlan_ifp) {
+		app_printf(pcb, "The GENEVE or VLAN interface does not exist.\n");
+		return -1;
+	}
+
+	vlan_parent = get_vlan_parent(vlan_ifp);
+
+	sc = gnv_ifp->if_softc;
+	if (NULL == sc->geneve_gw_ifp) {
+		app_printf(pcb, "The GENEVE interface has not been associated with a VLAN interface yet.\n");
+		return -1;
+	} else if ((vlan_ifp->if_flags & IFF_GENEVE_BIND) !=  IFF_GENEVE_BIND || vlan_ifp->geneve_vni == 0) {
+		app_printf(pcb, "The GENEVE interface has not been associated with a VLAN interface yet.\n");
+		return -1;
+	}
+	
+	sc->geneve_gw_ifp = NULL;
+	vlan_ifp->if_flags &= ~(IFF_GENEVE_BIND | IFF_PROMISC | IFF_PPROMISC | IFF_ALLMULTI);
+	vlan_parent->if_flags &= ~(IFF_PPROMISC | IFF_ALLMULTI);
+	vlan_ifp->geneve_vni = 0;
+
+	ret = geneve_set_promisc(vlan_ifp, 0);
+
+	app_printf(pcb, "Warning: please also clear geneve local forwarding table after this CLI.\n");
+
+	return ret;
+}
+
+int
+geneve_tunnel_is_bound_kern(void *pcb, char *tun_name)
+{
+    struct geneve_tunnel *geneve_tun = NULL;
+
+    GENEVE_DBG_ENTER("pcb: %p, tun_name: %s", pcb, tun_name);
+
+    LIST_FOREACH(geneve_tun, &gtep.tunnel_list, entries) {
+        if (!strncmp(geneve_tun->name, tun_name, MAX_TUNNEL_NAME_LEN)) {
+            if (geneve_tun->refcnt) {
+                GENEVE_DBG_ERR("This tunnel is in binding status.");
+                return 1;
+            } else {
+                GENEVE_DBG_INFO("This tunnel is not in binding status.");
+                return 0;
+            }
+        }
+    }
+
+    return 0;
+}
+
+int
+geneve_bind_kern(void* pcb, char *geneve_intf, char *tun_name)
+{
+    struct ifnet *geneve_realif = NULL;
+    struct geneve_softc  *geneve_softc = NULL;
+    struct geneve_tunnel *geneve_tun = NULL;
+    struct geneve_tunnel *tun_tmp = NULL;
+    int i;
+
+    GENEVE_DBG_ENTER("pcb: %p, geneve_intf: %s, tun_name: %s", pcb, geneve_intf, tun_name);
+
+    /* CAVEAT: geneve_intf should be system interface name, not array name */
+    geneve_realif = ifunit(geneve_intf);
+    if (!geneve_realif) {
+        GENEVE_DBG_ERR("This GENEVE interface does not exist.");
+        return -1;
+    }
+
+    geneve_softc = geneve_realif->if_softc;
+    if (!geneve_softc) {
+        GENEVE_DBG_ERR("This geneve collapsed.");
+        return -1;
+    }
+
+    LIST_FOREACH(tun_tmp, &gtep.tunnel_list, entries) {
+        if (!strncmp(tun_tmp->name, tun_name, strlen(tun_tmp->name))) {
+            geneve_tun = tun_tmp;
+            break;
+        }
+    }
+
+    if (!geneve_tun) {
+        GENEVE_DBG_ERR("This GENEVE tunnel does not exist.");
+        return -1;
+    }
+
+    for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; i++) {
+        if (!geneve_softc->geneve_tunl_tbl[i]) {
+            geneve_softc->geneve_tunl_tbl[i] = geneve_tun;
+            GENEVE_DBG_INFO("Kern: GENEVE bind ok, %s, softc %p.", geneve_intf, geneve_softc);
+            GENEVE_TUN_ACQUIRE(geneve_tun);
+            break;
+        }
+    }
+
+    if (i == GENEVE_VNI_MAX_TUNNEL) {
+        GENEVE_DBG_ERR("The GENEVE interface has been bound to %d tunnels. %d is the binding limit.", 
+                        GENEVE_VNI_MAX_TUNNEL, GENEVE_VNI_MAX_TUNNEL);
+        return -1;
+    }
+
+    return 0;
+}
+
+int no_geneve_bind_kern(void* pcb, char* gnv_intf, char* tun_name)
+{
+	struct ifnet* gnv_realif = NULL;
+	struct geneve_softc* gnv_softc = NULL;
+	struct geneve_tunnel* gnv_tun = NULL;
+	struct geneve_tunnel* tun_tmp = NULL;
+	int i;
+
+	/*CAVEAT: gnv_intf should be system interface name, not array name*/
+	gnv_realif = ifunit(gnv_intf);
+	if (NULL == gnv_realif) {
+		app_printf(pcb, "This geneve interface does not exist.\n");
+		return -1;
+	}
+
+	gnv_softc = gnv_realif->if_softc;
+	if (NULL == gnv_softc) {
+		app_printf(pcb, "This geneve collapsed.\n");
+		return -1;
+	}
+
+	LIST_FOREACH(tun_tmp, &gtep.tunnel_list, entries) {
+		if (!strncmp(tun_tmp->name, tun_name, MAX_TUNNEL_NAME_LEN)) {
+			gnv_tun = tun_tmp;
+			break;
+		}
+	}
+	if (NULL == gnv_tun) {
+		app_printf(pcb, "This geneve tunnel does not exist.\n");
+		return -1;
+	}
+
+	if (geneve_ftable_has_tunnel(gnv_softc, gnv_tun)) {
+		app_printf(pcb, "Before deleting the binding configuration, first remove the associated static GENEVE forwarding table for the GENEVE.\n");
+		return -1;
+	}
+
+	for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; ++i) {
+		if (gnv_tun == gnv_softc->geneve_tunl_tbl[i]) {
+			gnv_softc->geneve_tunl_tbl[i] = NULL;
+			geneve_ftable_flush(gnv_softc, 1, gnv_tun);
+			GENEVE_TUN_RELEASE(gnv_tun);
+			return 0;
+		}
+	}
+
+	app_printf(pcb, "This geneve interface has not been binded to this tunnel.\n");
+	return -1;
+
+}
+
+static int 
+geneve_join(struct geneve_tunnel *tunnel, union geneve_sockaddr *saddr, union geneve_sockaddr *raddr)
+{
+    union geneve_sockaddr laddr;
+    int ret;
+    struct sockopt sopt;
+    struct thread *td;
+
+    GENEVE_DBG_ENTER("tunnel: %s, saddr: %p, raddr: %p", tunnel->name, saddr, raddr);
+
+    laddr = *saddr;
+    td = curthread;
+
+    ret = socreate(laddr.sa.sa_family, &tunnel->sock, SOCK_DGRAM, IPPROTO_UDP, td->td_ucred, td, NULL);
+    if (ret) {
+        GENEVE_DBG_ERR("geneve join fail when create socket");
+        return ret;
+    }
+
+    if (tunnel->isipv6) {
+        struct ipv6_mreq mreq;
+
+        mreq.ipv6mr_multiaddr = raddr->in6.sin6_addr;
+        mreq.ipv6mr_interface = tunnel->ifp->if_index;
+
+        bzero(&sopt, sizeof(sopt));
+        sopt.sopt_dir = SOPT_SET;
+        sopt.sopt_level = IPPROTO_IPV6;
+        sopt.sopt_name = IPV6_JOIN_GROUP;
+        sopt.sopt_val = &mreq;
+        sopt.sopt_valsize = sizeof(mreq);
+        ret = sosetopt(tunnel->sock, &sopt);
+    } else {
+        struct ip_mreq mreq;
+
+        mreq.imr_multiaddr = raddr->in4.sin_addr;
+        mreq.imr_interface = saddr->in4.sin_addr;
+
+        bzero(&sopt, sizeof(sopt));
+        sopt.sopt_dir = SOPT_SET;
+        sopt.sopt_level = IPPROTO_IP;
+        sopt.sopt_name = IP_ADD_MEMBERSHIP;
+        sopt.sopt_val = &mreq;
+        sopt.sopt_valsize = sizeof(mreq);
+        ret = sosetopt(tunnel->sock, &sopt);
+    }
+
+    GENEVE_DBG_INFO("adding membership");
+
+    if (ret) {
+        GENEVE_DBG_ERR("kern add membership fail");
+    }
+
+    return ret;
+}
+
+static void geneve_leave(struct geneve_tunnel *tunnel, union geneve_sockaddr *saddr, union geneve_sockaddr *raddr)
+{
+    struct ip_mreq mreq;
+    struct sockopt sopt;
+    int ret;
+
+    GENEVE_DBG_ENTER("tunnel: %s, saddr: %p, raddr: %p", tunnel->name, saddr, raddr);
+
+    mreq.imr_multiaddr = raddr->in4.sin_addr;
+    mreq.imr_interface = saddr->in4.sin_addr;
+
+    bzero(&sopt, sizeof(sopt));
+    sopt.sopt_dir = SOPT_SET;
+    sopt.sopt_level = IPPROTO_IP;
+    sopt.sopt_name = IP_DROP_MEMBERSHIP;
+    sopt.sopt_val = &mreq;
+    sopt.sopt_valsize = sizeof(mreq);
+
+    ret = sosetopt(tunnel->sock, &sopt);
+
+    GENEVE_DBG_INFO("Deleting membership\n");
+
+    if (ret) {
+        GENEVE_DBG_ERR("kern add membership fail\n");
+    }
+
+    if (tunnel->sock) {
+        soclose(tunnel->sock);
+    }
+
+    tunnel->sock = NULL;
+
+    return;
+}
+
+int 
+geneve_need_fwd(struct ifnet *ifp, struct mbuf *m)
+{
+    struct ether_header *eh;
+
+    GENEVE_DBG_ENTER("ifp: %p, if_name: %s, m: %p", ifp, ifp->if_xname, m);
+
+    eh = mtod(m, struct ether_header *);
+    
+    if (!bcmp(IF_LLADDR(ifp), eh->ether_dhost, ETHER_ADDR_LEN)) {
+        return GENEVE_DST_LOCAL;
+    } else if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
+        return GENEVE_DST_FLOOD;
+    } else {
+        return GENEVE_DST_REMOTE;
+    }
+}
+
+/*
+ * if localip_addr == NULL, only check remote ip
+ * if remoteip_addr == NULL, only check local ip
+ * if both of them are not NULL, check both remote ip and local ip
+ */
+static struct geneve_tunnel*
+find_geneve_tunnel_by_ip(struct geneve_softc *sc, const struct sockaddr *localip_addr, const struct sockaddr *remoteip_addr)
+{
+    struct geneve_tunnel *geneve_tun = NULL;
+    int i;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, localip_addr: %p, remoteip_addr: %p", 
+                        sc, sc->geneve_ifp->if_xname, localip_addr, remoteip_addr);
+
+    if (!localip_addr && !remoteip_addr) {
+        return NULL;
+    }
+    
+    for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; i++) {
+        geneve_tun = sc->geneve_tunl_tbl[i];
+
+        if (!geneve_tun) {
+            continue;
+        }
+
+        if ((!localip_addr || geneve_sockaddr_in_equal(&geneve_tun->src_addr, localip_addr)) &&
+            (!remoteip_addr || geneve_sockaddr_in_equal(&geneve_tun->dst_addr, remoteip_addr))) {
+            return geneve_tun;
+        }
+    }
+
+    return NULL;
+}
+
+static struct geneve_tunnel*
+check_geneve_ip_on_tunnel(struct geneve_softc *sc, const struct sockaddr *source_addr, const struct sockaddr *dest_addr, int is_multicast_packet)
+{
+    struct geneve_tunnel *geneve_tun = NULL;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, source_addr: %p, dest_addr: %p, is_multicast_packet: %d", 
+                        sc, sc->geneve_ifp->if_xname, source_addr, dest_addr, is_multicast_packet);
+
+    if (is_multicast_packet) {
+        /* received a multicast package on multicast mode, 
+         * check whether the dest IP is our tunnel remote multicast ip*/
+        geneve_tun = find_geneve_tunnel_by_ip(sc, NULL, dest_addr);
+        if (!geneve_tun) {
+            return NULL;
+        }
+    } else {
+        /* check both dest IP and source IP */
+        geneve_tun = find_geneve_tunnel_by_ip(sc, dest_addr, source_addr);
+        if (!geneve_tun) {
+            return NULL;
+        }
+    }
+
+    return geneve_tun;
+}
+
+static void 
+geneve_l2_forward_tun2local(struct ifnet *ifp, struct mbuf *m) 
+{
+    struct geneve_softc *sc;
+    struct ifnet *local_ifp = NULL;
+
+    GENEVE_DBG_ENTER("ifp: %p, if_name: %s, m: %p", ifp, ifp->if_xname, m);
+
+    sc = ifp->if_softc;
+    local_ifp = sc->geneve_gw_ifp;
+
+    if (local_ifp == NULL) {
+        m_freem_atcp(m);
+        GENEVE_DBG_INFO("Local vlan not associated, vni %d.", sc->geneve_vni);
+        return;
+    }
+
+    GENEVE_DBG_INFO("tunnel to local %s, vni %d", local_ifp->if_xname, sc->geneve_vni);
+
+    /* send out inner packet to local VLAN */
+    (*local_ifp->atcp_if_output)(local_ifp, m);
+}
+
+/* Only process Local ifp ---->  tunnel L2 forward/flood 
+ *
+ * APV geneve gw only process 2 case:
+ *     1, local ---> tunnel
+ *     2, tunnel ----> local
+ * 
+ * L2 forward between local MACs and tunnel MACs will never be done.
+ * This is based on one premption that tunnels are full-meshed.
+ * And local ifp is connected with a switch which performs local L2 forward among local RS.
+ */
+int 
+geneve_l2_fwd_local2tun(struct ifnet *ifp, struct mbuf *m, int flood)
+{
+    struct rm_priotracker tracker;
+    union  geneve_sockaddr sa;
+    struct geneve_softc *sc;
+    struct geneve_ftable_entry *fe;
+    struct ifnet *mcifp;
+    struct ether_header *eh;
+    int isipv4, error, multicast = 0;
+
+    GENEVE_DBG_ENTER("ifp: %p, if_xname: %s, m: %p, flood: %d", ifp, ifp->if_xname, m, flood);
+
+    sc = ifp->if_softc;
+    eh = mtod(m, struct ether_header *);
+    fe = NULL;
+    mcifp = NULL;
+
+    ETHER_BPF_MTAP(ifp, m);
+
+    if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+        m_freem(m);
+        GENEVE_DBG_ERR("ENETDOWN");
+        return ENETDOWN;
+    }
+
+    if (flood) {
+        GENEVE_DBG_INFO("l2flooding to tunnels, from ifp %s, vni %d", ifp->if_xname, ifp->geneve_vni);
+        sc->geneve_stat.geneve_local_pkt_flood++;
+    } else {
+        GENEVE_DBG_INFO("l2forwarding from ifp %s, vni %d", ifp->if_xname, ifp->geneve_vni);
+        sc->geneve_stat.geneve_local_pkt_fwd++;
+    }
+
+    if ((m->m_flags & (M_BCAST | M_MCAST)) == 0) {
+        fe = geneve_ftable_entry_lookup(sc, eh->ether_dhost);
+    }
+
+    if (!fe) {
+        int i;
+        struct mbuf *n;
+        struct geneve_tunnel *geneve_tun = NULL;
+
+        GENEVE_ACQUIRE(sc);
+
+        for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; i++) {
+            geneve_tun = sc->geneve_tunl_tbl[i];
+
+            if (geneve_tun) {
+                GENEVE_DBG_INFO("vni %d flooding tunnel %s", sc->geneve_vni, geneve_tun->name);
+
+                n = m_dup(m, M_NOWAIT);
+                if (!n) {
+                    GENEVE_DBG_ERR("dup mbuf failed");
+                    continue;
+                }
+
+                geneve_sockaddr_copy(&sa, &geneve_tun->dst_addr.sa);
+                isipv4 = (GENEVE_SOCKADDR_IS_IPV4(&sa) != 0);
+
+                if (geneve_sockaddr_in_multicast(&sa) != 0) {
+                    mcifp = geneve_tun->ifp;
+                    if (!mcifp) {
+                        GENEVE_DBG_ERR("warning: multicast dst without multicast output interface, tunnel: %s", geneve_tun->name);
+                        return -1;
+                    }
+                    multicast = 1;
+                } else {
+                    multicast = 0;
+                }
+
+                if (isipv4) {
+                    error = geneve_encap4_send(sc, geneve_tun, &sa, n, multicast);
+                } else {
+                    error = geneve_encap6_send(sc, geneve_tun, &sa, n, multicast);
+                }
+
+                if (error) {
+                    break;
+                }
+            }
+        }
+
+        m_freem_atcp(m);
+        geneve_release(sc);
+        return error;
+    }
+
+    /* never do local L2 forwarding, only between geneve/vlan */
+    if (fe->flags & GENEVE_FE_FLAG_LOCAL) {
+        GENEVE_DBG_ERR("STRANGE to come here %s, vni %d", sc->geneve_gw_ifp->if_xname, sc->geneve_vni);
+        return -1;
+    }
+
+    geneve_sockaddr_copy(&sa, &fe->raddr.sa);
+
+    GENEVE_DBG_INFO("forwarding to tunnel %s", fe->tunnel->name);
+
+    isipv4 = (GENEVE_SOCKADDR_IS_IPV4(&sa) != 0);
+
+    GENEVE_ACQUIRE(sc);
+
+    if (isipv4 != 0) {
+        error = geneve_encap4_send(sc, fe->tunnel, &sa, m, multicast);
+    } else {
+        error = geneve_encap6_send(sc, fe->tunnel, &sa, m, multicast);
+    }
+
+    geneve_release(sc);
+
+    return error;
+}
+
+struct ifnet * 
+geneve_local_learn(struct ifnet *ifp, struct mbuf *m)
+{
+    struct geneve_softc* sc;
+    struct ether_header *eh;
+
+    GENEVE_DBG_ENTER("ifp: %p, if_name: %s, m: %p", ifp, ifp->if_xname, m);
+
+    sc = geneve_lookup_softc(ifp->geneve_vni);
+
+    if (!sc) {
+        GENEVE_DBG_ERR("geneve_lookup failed, vni %d", ifp->geneve_vni);
+        return NULL;
+    }
+
+    sc->geneve_stat.geneve_local_pkt_in++;
+
+    eh = mtod(m, struct ether_header *);
+
+    if (geneve_learn == GENEVE_LEARN_ON) {
+        sc->geneve_stat.geneve_local_learn++;
+
+        if (geneve_ftable_update(sc, NULL, NULL, eh->ether_shost, GENEVE_FE_FLAG_LOCAL | GENEVE_FE_FLAG_DYNAMIC)) {
+            GENEVE_DBG_ERR("warning: geneve learned failed.");
+        }
+    }
+
+    return sc->geneve_ifp;
+}
+
+void
+geneve_learn_fwd(int vni, struct mbuf *m, struct ip *ip, struct ip6_hdr *ip6, int isipv6)
+{
+    struct geneve_softc *sc;
+    struct ifnet *ifp;
+    struct geneve_tunnel* geneve_tun = NULL;
+    struct ether_header *eh;
+    struct mbuf *n;
+    int error, is_multicast = 0;
+    union geneve_sockaddr gtep_addr;
+    union geneve_sockaddr localip;
+
+    GENEVE_DBG_ENTER("vni: %d, m: %p, ip: %p, ip6: %p, isipv6: %d", vni, m, ip, ip6, isipv6);
+
+    sc = geneve_lookup_softc(vni);
+    if (!sc) {
+        m_freem_atcp(m);
+        GENEVE_DBG_ERR("cannot find geneve softc, vni %d", vni);
+        return;
+    }
+
+    ifp = sc->geneve_ifp;
+    eh = mtod(m, struct ether_header *);
+
+    if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+        error = ENETDOWN;
+        m_freem_atcp(m);
+        GENEVE_DBG_ERR("ENETDOWN");
+        goto out;
+    } else if (ifp == m->m_pkthdr.rcvif) {
+        /* XXX Does not catch more complex loops. */
+        error = EDEADLK;
+        m_freem_atcp(m);
+        GENEVE_DBG_ERR("EDEADLK");
+        goto out;
+    }
+
+    if (isipv6) {
+        gtep_addr.in6.sin6_family = AF_INET6;
+        gtep_addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+        gtep_addr.in6.sin6_addr = ip6->ip6_src;
+
+        localip.in6.sin6_family = AF_INET6;
+        localip.in6.sin6_len = sizeof(struct sockaddr_in6);
+        localip.in6.sin6_addr = ip6->ip6_dst;
+
+        if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
+            is_multicast = 1;
+        }
+    } else {
+        gtep_addr.in4.sin_family = AF_INET;
+        gtep_addr.in4.sin_len = sizeof(struct sockaddr_in);
+        gtep_addr.in4.sin_addr.s_addr = ip->ip_src.s_addr;
+
+        localip.in4.sin_family = AF_INET;
+        localip.in4.sin_len = sizeof(struct sockaddr_in);
+        localip.in4.sin_addr.s_addr = ip->ip_dst.s_addr;
+
+        if (ntohl(ip->ip_dst.s_addr) > 0xe0000000 && ntohl(ip->ip_dst.s_addr) < 0xefffffff) {
+            is_multicast = 1;
+        }
+    }
+
+    geneve_tun = check_geneve_ip_on_tunnel(sc, &gtep_addr.sa, &localip.sa, is_multicast);
+    if (!geneve_tun) {
+        m_freem_atcp(m);
+        sc->geneve_stat.geneve_not_tun_ip++;
+        GENEVE_DBG_ERR("not found gennel tunnel");
+        goto out;
+    }
+
+    if (geneve_learn == GENEVE_LEARN_ON) {
+        geneve_ftable_update(sc, &gtep_addr.sa, geneve_tun, eh->ether_shost, GENEVE_FE_FLAG_REMOTE | GENEVE_FE_FLAG_DYNAMIC);
+        sc->geneve_stat.geneve_tun_learn++;
+    }
+
+    m_clrprotoflags(m);
+    m->m_pkthdr.rcvif = ifp;
+    M_SETFIB(m, ifp->if_fib);
+
+    ifp->if_ibytes += m->m_pkthdr.len;  /* Has already stripped tunnel header. */
+    ifp->if_ipackets++;
+    sc->geneve_stat.geneve_tun_pkt_in++;
+
+    /* Inner packet processing from very beginning
+     *   1, to local (geneve intf mac), re-input (Layer 3)
+     *   2, multicast or broadcast, dup to forward and re-input
+     *   3, to other unicast mac, forward (Layer 2)
+     */
+    switch(geneve_need_fwd(ifp, m)) {
+        case GENEVE_DST_REMOTE:
+            geneve_l2_forward_tun2local(ifp, m);
+            sc->geneve_stat.geneve_tun_pkt_fwd++;
+            return;
+        case GENEVE_DST_FLOOD:
+            n = m_dup(m, M_NOWAIT);
+            geneve_l2_forward_tun2local(ifp, n);
+            sc->geneve_stat.geneve_tun_pkt_flood++;
+            break;
+        case GENEVE_DST_LOCAL:
+        default:
+            break;
+    }
+
+    (*ifp->if_input)(ifp, m);
+
+out:
+    geneve_release(sc);
+    return;
+}
+
+int
+geneve_tunnel_kern(void *pcb, char *tun_name, char *localip, char *remoteip)
+{
+    struct geneve_tunnel *tunnel = NULL;
+    union geneve_sockaddr addr_src = {{0}};
+    union geneve_sockaddr addr_dst = {{0}};
+    struct in_addr local, remote;
+    struct in6_addr local6, remote6;
+    int isipv6, rtn;
+    struct ifaddr* ifa;
+
+    GENEVE_DBG_ENTER("pcb: %p, tun_name: %s, localip: %s, remoteip: %s", pcb, tun_name, localip, remoteip);
+
+    /* ip processing */
+    if(strstr(localip, ".") != NULL) {
+        isipv6 = 0;
+        if (inet_aton(localip, &local) != 1) {
+            GENEVE_DBG_ERR("convert localip failed.");
+            return -1;
+        }
+    } else {
+        isipv6 = 1;
+        if (inet_pton(AF_INET6, localip, &local6) != 1) {
+            GENEVE_DBG_ERR("convert localip6 failed.");
+            return -1;
+        }
+    }
+
+    if(strstr(remoteip, ".") != NULL) {
+        if (inet_aton (remoteip, &remote) != 1) {
+            GENEVE_DBG_ERR("convert remoteip failed.");
+            return -1;
+        }
+    } else {
+        if (inet_pton(AF_INET6, remoteip, &remote6) != 1) {
+            GENEVE_DBG_ERR("convert remoteip6 failed.");
+            return -1;
+        }
+    }
+    
+    if (!isipv6) {
+        addr_src.in4.sin_len = sizeof(struct sockaddr_in);
+        addr_src.in4.sin_family = AF_INET;
+        addr_src.in4.sin_addr = local;
+
+        addr_dst.in4.sin_len = sizeof(struct sockaddr_in);
+        addr_dst.in4.sin_family = AF_INET;
+        addr_dst.in4.sin_addr = remote;
+        addr_dst.in4.sin_port = htons((uint32_t)gtep.geneve_port);
+    } else {
+        addr_src.in6.sin6_len = sizeof(struct sockaddr_in6);
+        addr_src.in6.sin6_family = AF_INET6;
+        addr_src.in6.sin6_addr = local6;
+
+        addr_dst.in6.sin6_len = sizeof(struct sockaddr_in6);
+        addr_dst.in6.sin6_family = AF_INET6;
+        addr_dst.in6.sin6_addr = remote6;
+        addr_dst.in6.sin6_port = htons((uint32_t)gtep.geneve_port);
+    }
+
+    /* Allocate new tunnel entry */
+    tunnel = malloc(sizeof(struct geneve_tunnel), M_GENEVE, M_ZERO | M_NOWAIT);
+    if (!tunnel) {
+        GENEVE_DBG_ERR("geneve tunnel alloc failed!");
+        return -1;
+    }
+
+    bzero(tunnel, sizeof(struct geneve_tunnel));
+
+    tunnel->isipv6 = isipv6;
+    strncpy(tunnel->name, tun_name, strlen(tun_name));
+    tunnel->dst_addr = addr_dst;
+    tunnel->src_addr = addr_src;
+    rm_init(&tunnel->lock, tun_name);
+
+    refcount_init(&tunnel->refcnt, 0);
+
+    LIST_INSERT_HEAD(&gtep.tunnel_list, tunnel, entries);
+
+    /* update multicast output interface, obtained from source iP address. */
+    ifa = ifa_ifwithaddr(&addr_src.sa);
+    tunnel->ifp = ifa->ifa_ifp;
+    ifa_free(ifa);
+    
+    GENEVE_DBG_INFO("geneve output interface: %s", tunnel->ifp->if_xname);
+
+    if (geneve_sockaddr_in_multicast(&addr_dst)) {
+        /*setup multicast structure*/
+        if (!isipv6) {
+            tunnel->im4o = malloc(sizeof(struct ip_moptions), M_GENEVE, M_ZERO | M_WAITOK);
+            tunnel->im4o->imo_multicast_ifp = tunnel->ifp;
+            tunnel->im4o->imo_multicast_ttl = IPDEFTTL;
+            tunnel->im4o->imo_multicast_vif = -1;
+        } else {
+            tunnel->im6o = malloc(sizeof(struct ip6_moptions), M_GENEVE, M_ZERO | M_WAITOK);
+            tunnel->im6o->im6o_multicast_ifp  = tunnel->ifp;
+            tunnel->im6o->im6o_multicast_hlim = IPDEFTTL;
+        }
+
+        rtn = geneve_join(tunnel, &addr_src, &addr_dst);
+        if (rtn) {
+            LIST_REMOVE(tunnel, entries);
+            rm_destroy(&tunnel->lock);
+            free(tunnel, M_GENEVE);
+            GENEVE_DBG_ERR("Kern: geneve join failed.\n");
+            return rtn;
+        }
+    }
+
+    return 0;
+}
+
+int
+no_geneve_tunnel_kern(void *pcb, char *tun_name)
+{
+    struct geneve_tunnel *geneve_tun = NULL;
+
+    GENEVE_DBG_ENTER("pcb: %p, tun_name: %s", pcb, tun_name);
+    
+    LIST_FOREACH(geneve_tun, &gtep.tunnel_list, entries) {
+        if (!strncmp(geneve_tun->name, tun_name, MAX_TUNNEL_NAME_LEN)) {
+            if (geneve_tun->refcnt) {
+                return -2;
+            } else {
+                if (geneve_sockaddr_in_multicast(&geneve_tun->dst_addr)) {
+                    GENEVE_DBG_INFO("geneve leaving.");
+                    geneve_leave(geneve_tun, &geneve_tun->src_addr, &geneve_tun->dst_addr);
+
+                    /* free multicast structure */
+                    if (geneve_tun->im4o) {
+                        free(geneve_tun->im4o, M_GENEVE);
+                    }
+                    if (geneve_tun->im6o) {
+                        free(geneve_tun->im6o, M_GENEVE);
+                    }
+                }
+
+                LIST_REMOVE(geneve_tun, entries);
+                rm_destroy(&geneve_tun->lock);
+                free(geneve_tun, M_GENEVE);
+
+                GENEVE_DBG_INFO("This tunnel is successfully deleted.");
+
+                return 0;
+            }
+        }
+    }
+
+    return -1;
+}
+
+int
+create_geneve_if(void *pcb, uint32_t geneve_num)
+{
+    int err = 0;
+    struct ifnet *ifp;
+    char name[IFNAMSIZ];
+    struct cafw_share *ca_p = NULL;
+
+    GENEVE_DBG_ENTER("pcb: %p, geneve_num: %d", pcb, geneve_num);
+
+    snprintf(name, IFNAMSIZ, "%s%d", geneve_name, geneve_num);
+
+    ifp = ifunit_ref(name);
+    if (ifp) {
+        ifp->if_link_state = LINK_STATE_UP;     /* GENEVE interface should always be UP */
+    } else {
+        err = geneve_clone_create(geneve_cloner, geneve_num, NULL);
+    }
+
+    if (!err && clickaddresses) {
+        ca_p = &clickaddresses->cafw_share;
+        ca_p->ifnodes[geneve_num + CAFW_GENEVE_OFFSET] = cafw_ifnode_new(geneve_num + CAFW_GENEVE_OFFSET);
+        if (ca_p->ifnodes[geneve_num+ CAFW_GENEVE_OFFSET] == NULL) {
+            GENEVE_DBG_ERR("geneve %d creating cafw ifnode failed.", geneve_num);
+        }
+    }
+
+    return err;
+}
+
+int
+destroy_geneve_if(void *pcb, uint32_t geneve_num)
+{
+    struct ifnet *geneve_if = NULL;
+    char geneve_name[IFNAMSIZ];
+
+    GENEVE_DBG_ENTER("pcb: %p, geneve_num: %d", pcb, geneve_num);
+
+    snprintf(geneve_name, IFNAMSIZ, "geneve%d", geneve_num);
+
+    geneve_if = ifunit(geneve_name);
+    if (!geneve_if) {
+        GENEVE_DBG_ERR("This geneve interface doesn't exist.");
+        return -1;
+    }
+    
+    geneve_clone_destroy(geneve_if);
+
+    return 0;
+}
+
+static void 
+gtep_init(void)
+{
+    int i;
+
+    GENEVE_DBG_ENTER();
+    
+    if (gtep_inited) {
+        return;
+    }
+
+    gtep.geneve_port = GENEVE_DEFAULT_PORT;
+    gtep.tunnel_num = 0;
+    gtep.vni_num = 0;
+
+    rm_init(&gtep.gtep_lock, "gtep_lock");
+
+    LIST_INIT(&gtep.tunnel_list);
+    for (i = 0; i < GENEVE_SO_VNI_HASH_SIZE; i++) {
+        LIST_INIT(&gtep.vni_hash[i]);
+    }
+
+    gtep_inited = 1;
+    
+    return;
+}
+
+static int
+geneve_check_vni(uint32_t vni)
+{
+    GENEVE_DBG_ENTER("vni: %d", vni);
+    return (vni >= GENEVE_VNI_MAX);
+}
+
+static int
+geneve_ctrl_set_vni(struct geneve_softc *sc, void *arg)
+{
+    struct ifgenevecmd *cmd;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, arg: %p", sc, sc->geneve_ifp->if_xname, arg);
+
+    cmd = arg;
+ 
+    if (geneve_check_vni(cmd->cmd_vni) != 0) {
+        GENEVE_DBG_ERR();
+        return EINVAL;
+    }
+
+    sc->geneve_vni = cmd->cmd_vni;
+    if_dpdk_set_geneve_vni(sc->dpdk_host_ctx, sc->geneve_vni);
+
+    /*initialize geneve here.*/
+    geneve_init((void*)sc);
+
+    return 0;
+}
+
+static int
+geneve_ioctl_ifflags(struct geneve_softc *sc)
+{
+    struct ifnet *ifp;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+
+    ifp = sc->geneve_ifp;
+
+    if (ifp->if_flags & IFF_UP) {
+        if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+            geneve_init(sc);
+        }
+    } else {
+        if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+            geneve_teardown(sc);
+        }
+    }
+
+    return 0;
+}
+
+static int 
+geneve_ioctl_drvspec(struct geneve_softc *sc, struct ifdrv *ifd, int get)
+{
+    const struct geneve_control *vc;
+    union {
+        struct ifgenevecfg   cfg;
+        struct ifgenevecmd   cmd;
+    } args;
+    int out, error;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, ifd: %s, get: %d", sc, sc->geneve_ifp->if_xname, ifd->ifd_name, get);
+
+    if (ifd->ifd_cmd >= geneve_control_table_size) {
+        GENEVE_DBG_ERR();
+        return EINVAL;
+    }
+
+    bzero(&args, sizeof(args));
+    vc = &geneve_control_table[ifd->ifd_cmd];
+
+    out = (vc->c_flags & GENEVE_CTRL_FLAG_COPYOUT) != 0;
+    if ((get != 0 && out == 0) || (get == 0 && out != 0)) {
+        GENEVE_DBG_ERR("out: %d", out);
+        return EINVAL;
+    }
+
+    if (ifd->ifd_len != vc->c_argsize || ifd->ifd_len > sizeof(args)) {
+        GENEVE_DBG_ERR();
+        return EINVAL;
+    }
+
+    if (vc->c_flags & GENEVE_CTRL_FLAG_COPYIN) {
+        error = copyin(ifd->ifd_data, &args, ifd->ifd_len);
+        if (error) {
+            GENEVE_DBG_ERR("error: %d", error);
+            return error;
+        }
+    }
+
+    error = vc->c_func(sc, &args);
+    if (error) {
+        GENEVE_DBG_ERR("error: %d", error);
+        return error;
+    }
+
+    if (vc->c_flags & GENEVE_CTRL_FLAG_COPYOUT) {
+        error = copyout(&args, ifd->ifd_data, ifd->ifd_len);
+        if (error) {
+            GENEVE_DBG_ERR("error: %d", error);
+            return error;
+        }
+    }
+
+    return 0;
+}
+
+static int
+geneve_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+    struct geneve_softc *sc;
+    struct ifreq *ifr;
+    struct ifdrv *ifd;
+    int error;
+
+    GENEVE_DBG_ENTER("ifp: %p, if_name: %s, cmd: %lu", ifp, ifp->if_xname, cmd);
+
+    sc = ifp->if_softc;
+    ifr = (struct ifreq *) data;
+    ifd = (struct ifdrv *) data;
+
+    switch (cmd) {
+        case SIOCADDMULTI:
+        case SIOCDELMULTI:
+            error = 0;
+            break;
+        case SIOCGDRVSPEC:
+        case SIOCSDRVSPEC:
+            error = geneve_ioctl_drvspec(sc, ifd, cmd == SIOCGDRVSPEC);
+            break;
+        case SIOCSIFFLAGS:
+            error = geneve_ioctl_ifflags(sc);
+            break;
+        case SIOCALIFADDR:
+        case SIOCSIFADDR:
+        default:
+            error = ether_ioctl(ifp, cmd, data);
+            break;
+    }
+
+    return error;
+}
+
+/* BMV: Taken from if_bridge. */
+static uint32_t
+geneve_mac_hash(struct geneve_softc *sc, const uint8_t *addr)
+{
+    uint32_t a = 0x9e3779b9, b = 0x9e3779b9, c = sc->geneve_ftable_hash_key;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, addr: %p", sc, sc->geneve_ifp->if_xname, addr);
+
+    b += addr[5] << 8;
+    b += addr[4];
+    a += addr[3] << 24;
+    a += addr[2] << 16;
+    a += addr[1] << 8;
+    a += addr[0];
+
+/*
+ * The following hash function is adapted from "Hash Functions" by Bob Jenkins
+ * ("Algorithm Alley", Dr. Dobbs Journal, September 1997).
+ */
+#define mix(a, b, c)                            \
+do {                                    \
+    a -= b; a -= c; a ^= (c >> 13);                 \
+    b -= c; b -= a; b ^= (a << 8);                  \
+    c -= a; c -= b; c ^= (b >> 13);                 \
+    a -= b; a -= c; a ^= (c >> 12);                 \
+    b -= c; b -= a; b ^= (a << 16);                 \
+    c -= a; c -= b; c ^= (b >> 5);                  \
+    a -= b; a -= c; a ^= (c >> 3);                  \
+    b -= c; b -= a; b ^= (a << 10);                 \
+    c -= a; c -= b; c ^= (b >> 15);                 \
+} while (0)
+
+    mix(a, b, c);
+
+#undef mix
+
+    return (c);
+}
+
+void 
+geneve_get_random_mac_addr(uint8_t *dst_mac_addr)
+{
+    uint8_t mac_addr[ETHER_ADDR_LEN] = {0};
+
+    GENEVE_DBG_ENTER("dst_mac_addr: %p", dst_mac_addr);
+
+    arc4rand(mac_addr, ETHER_ADDR_LEN, 1);
+    mac_addr[0] &= ~1;
+    mac_addr[0] |= 2;
+    
+    bcopy(mac_addr, dst_mac_addr, ETHER_ADDR_LEN);
+}
+
+static void
+geneve_ftable_init(struct geneve_softc *sc)
+{
+    int i;
+
+    GENEVE_DBG_ENTER("sc: %p", sc);
+
+    /*ftable init*/
+    sc->geneve_ftable = malloc(sizeof(struct geneve_ftable_head) * GENEVE_SC_FTABLE_SIZE, M_GENEVE, M_ZERO | M_WAITOK);
+    for (i = 0; i < GENEVE_SC_FTABLE_SIZE; i++) {
+        LIST_INIT(&sc->geneve_ftable[i]);
+    }
+    
+    sc->geneve_ftable_hash_key = arc4random();
+
+    /*ftable lock init*/
+    sc->geneve_ftbl_lock = malloc(sizeof(click_rwlock_t) * GENEVE_SC_FTABLE_SIZE, M_GENEVE, M_ZERO | M_WAITOK);
+    for (i = 0; i < GENEVE_SC_FTABLE_SIZE; i++) {
+        click_rwlock_init(&sc->geneve_ftbl_lock[i]);
+    }
+}
+
+static void
+geneve_ftable_fini(struct geneve_softc *sc)
+{
+    int i;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+
+    for (i = 0; i < GENEVE_SC_FTABLE_SIZE; i++) {
+        KASSERT(LIST_EMPTY(&sc->geneve_ftable[i]), ("%s: geneve %p ftable[%d] not empty", __func__, sc, i));
+    }
+    MPASS(sc->geneve_ftable_cnt == 0);
+
+    free(sc->geneve_ftable, M_GENEVE);
+    sc->geneve_ftable = NULL;
+    
+    free(sc->geneve_ftbl_lock, M_GENEVE);
+    sc->geneve_ftbl_lock = NULL;
+}
+
+static void
+geneve_ftable_flush(struct geneve_softc *sc, int all, struct geneve_tunnel *tun)
+{
+    struct geneve_ftable_entry *fe, *tfe;
+    int i;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, all: %d, tun: %s", sc, sc->geneve_ifp->if_xname, all, tun->name);
+
+    for (i = 0; i < GENEVE_SC_FTABLE_SIZE; i++) {
+        GENEVE_FTBL_WLOCK(sc, i);
+        
+        LIST_FOREACH_SAFE(fe, &sc->geneve_ftable[i], hash, tfe) {
+            if ((all || GENEVE_FE_IS_DYNAMIC(fe)) && (tun == NULL || fe->tunnel == tun)) {
+                geneve_ftable_entry_destroy(sc, fe);
+            }
+        }
+
+        GENEVE_FTBL_WUNLOCK(sc, i);
+    }
+}
+
+static int
+geneve_ftable_has_tunnel(struct geneve_softc *sc, struct geneve_tunnel *gnv_tun)
+{
+	struct geneve_ftable_entry *fe, *tfe;
+	int i;
+
+	for (i = 0; i < GENEVE_SC_FTABLE_SIZE; ++i) {
+		GENEVE_FTBL_WLOCK(sc, i);
+		
+		LIST_FOREACH_SAFE(fe, &sc->geneve_ftable[i], hash, tfe) {
+			if (!GENEVE_FE_IS_DYNAMIC(fe) && fe->tunnel == gnv_tun) { // here
+				GENEVE_FTBL_WUNLOCK(sc, i); // here
+				return 1;
+			}
+		}
+		GENEVE_FTBL_WUNLOCK(sc, i);
+	}
 	return 0;
-}
\ No newline at end of file
+}
+
+static void
+geneve_ftable_entry_destroy(struct geneve_softc *sc, struct geneve_ftable_entry *fe)
+{
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, fe: %p, mac: %02x:%02x:%02x:%02x:%02x:%02x", 
+                        sc, sc->geneve_ifp->if_xname, fe, fe->mac[0], fe->mac[1], fe->mac[2], fe->mac[3], fe->mac[4], fe->mac[5]);
+    sc->geneve_ftable_cnt--;
+    LIST_REMOVE(fe, hash);
+    geneve_ftable_entry_free(fe);
+}
+
+static __inline struct geneve_ftable_entry *
+geneve_ftable_entry_alloc(void)
+{
+    GENEVE_DBG_ENTER();
+    return (struct geneve_ftable_entry *)uma_zalloc(geneve_ftable_entry_zone, M_NOWAIT | M_ZERO);
+}
+
+static __inline void
+geneve_ftable_entry_free(struct geneve_ftable_entry *fe)
+{
+    GENEVE_DBG_ENTER("fe: %p, mac: %02x:%02x:%02x:%02x:%02x:%02x", 
+                        fe, fe->mac[0], fe->mac[1], fe->mac[2], fe->mac[3], fe->mac[4], fe->mac[5]);
+    uma_zfree(geneve_ftable_entry_zone, fe);
+}
+
+static int
+geneve_ftable_addr_cmp(const uint8_t *a, const uint8_t *b)
+{
+    int i, d;
+
+    GENEVE_DBG_ENTER("a: %p, b: %p", a, b);
+
+    for (i = 0, d = 0; i < ETHER_ADDR_LEN && d == 0; i++)
+        d = ((int)a[i]) - ((int)b[i]);
+
+    return (d);
+}
+
+static int
+geneve_ftable_entry_insert(struct geneve_softc *sc, struct geneve_ftable_entry *fe)
+{
+    struct geneve_ftable_entry *lfe;
+    uint32_t hash;
+    int dir;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, fe: %p, mac: %02x:%02x:%02x:%02x:%02x:%02x", 
+                        sc, sc->geneve_ifp->if_xname, fe, fe->mac[0], fe->mac[1], fe->mac[2], fe->mac[3], fe->mac[4], fe->mac[5]);
+    
+    hash = GENEVE_SC_FTABLE_HASH(sc, fe->mac);
+    
+    GENEVE_FTBL_WLOCK(sc, hash);
+
+    lfe = LIST_FIRST(&sc->geneve_ftable[hash]);
+    if (lfe == NULL) {
+        LIST_INSERT_HEAD(&sc->geneve_ftable[hash], fe, hash);
+        goto out;
+    }
+
+    do {
+        dir = geneve_ftable_addr_cmp(fe->mac, lfe->mac);
+        if (dir == 0) {
+            GENEVE_FTBL_WUNLOCK(sc, hash);
+            return EEXIST;
+        }
+        if (dir > 0) {
+            LIST_INSERT_BEFORE(lfe, fe, hash);
+            goto out;
+        } else if (LIST_NEXT(lfe, hash) == NULL) {
+            LIST_INSERT_AFTER(lfe, fe, hash);
+            goto out;
+        } else
+            lfe = LIST_NEXT(lfe, hash);
+    } while (lfe != NULL);
+
+out:
+    GENEVE_FTBL_WUNLOCK(sc, hash);
+    sc->geneve_ftable_cnt++;
+
+    return 0;
+}
+
+static struct geneve_ftable_entry *
+geneve_ftable_entry_lookup(struct geneve_softc *sc, const uint8_t *mac)
+{
+    struct geneve_ftable_entry *fe;
+    uint32_t hash;
+    int dir;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, mac: %02x:%02x:%02x:%02x:%02x:%02x",
+                        sc, sc->geneve_ifp->if_xname, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+    
+    hash = GENEVE_SC_FTABLE_HASH(sc, mac);
+
+    GENEVE_FTBL_RLOCK(sc, hash);
+
+    LIST_FOREACH(fe, &sc->geneve_ftable[hash], hash) {
+        dir = geneve_ftable_addr_cmp(mac, fe->mac);
+        if (dir == 0) {
+            GENEVE_FTBL_RUNLOCK(sc, hash);
+            return fe;
+        }
+        if (dir > 0) {
+            break;
+        }
+    }
+
+    GENEVE_FTBL_RUNLOCK(sc, hash);
+
+    return NULL;
+}
+
+static void
+geneve_ftable_entry_dump(struct geneve_ftable_entry *fe, struct sbuf *sb)
+{
+    char buf[64];
+    const union geneve_sockaddr *sa;
+    const void *addr;
+    int i, len, af, width;
+
+    GENEVE_DBG_ENTER("fe: %p, mac: %02x:%02x:%02x:%02x:%02x:%02x, sb: %p", 
+                        fe, fe->mac[0], fe->mac[1], fe->mac[2], fe->mac[3], fe->mac[4], fe->mac[5], sb);
+
+    sa = &fe->raddr;
+    af = sa->sa.sa_family;
+    len = sbuf_len(sb);
+
+    sbuf_printf(sb, "%c 0x%02X ", GENEVE_FE_IS_DYNAMIC(fe) ? 'D' : 'S', fe->flags);
+
+    for (i = 0; i < ETHER_ADDR_LEN - 1; i++)
+        sbuf_printf(sb, "%02X:", fe->mac[i]);
+    sbuf_printf(sb, "%02X ", fe->mac[i]);
+
+    if (af == AF_INET) {
+        addr = &sa->in4.sin_addr;
+        width = INET_ADDRSTRLEN - 1;
+    } else {
+        addr = &sa->in6.sin6_addr;
+        width = INET6_ADDRSTRLEN - 1;
+    }
+
+    inet_ntop(af, addr, buf, sizeof(buf));
+    sbuf_printf(sb, "%*s ", width, buf);
+
+    sbuf_printf(sb, "%08ld", fe->expire);
+
+    sbuf_putc(sb, '\n');
+
+    /* Truncate a partial line. */
+    if (sbuf_error(sb) != 0) {
+        sbuf_setpos(sb, len);
+    }
+}
+
+static void
+geneve_ftable_entry_init(struct geneve_softc *sc, struct geneve_ftable_entry *fe,
+    const uint8_t *mac, const struct sockaddr *sa, uint32_t flags)
+{
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, fe: %p, mac: %02x:%02x:%02x:%02x:%02x:%02x, sa: %p, flags: %u",
+                        sc, sc->geneve_ifp->if_xname, fe, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], sa, flags);
+    fe->flags = flags;
+    fe->expire = time_uptime + sc->geneve_ftable_timeout;
+    memcpy(fe->mac, mac, ETHER_HDR_LEN);
+    if (fe->flags & GENEVE_FE_FLAG_REMOTE) {
+        geneve_sockaddr_copy(&fe->raddr, sa);
+    }
+}
+
+static void
+geneve_ftable_expire(struct geneve_softc *sc)
+{
+    struct geneve_ftable_entry *fe, *tfe;
+    int i;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+
+    for (i = 0; i < GENEVE_SC_FTABLE_SIZE; i++) {
+        GENEVE_FTBL_WLOCK(sc, i);
+
+        LIST_FOREACH_SAFE(fe, &sc->geneve_ftable[i], hash, tfe) {
+            if (GENEVE_FE_IS_DYNAMIC(fe) && time_uptime >= fe->expire) {
+                geneve_ftable_entry_destroy(sc, fe);
+                GENEVE_DBG_INFO("mac: %02x:%02x:%02x:%02x:%02x:%02x", 
+                                fe->mac[0], fe->mac[1], fe->mac[2], fe->mac[3], fe->mac[4], fe->mac[5]);
+            }
+        }
+
+        GENEVE_FTBL_WUNLOCK(sc, i);
+    }
+}
+
+static int
+geneve_ftable_update_locked(struct geneve_softc *sc, const struct sockaddr *gtep_addr, struct geneve_tunnel *geneve_tun,
+                            const uint8_t *mac, struct rm_priotracker *tracker, uint32_t flags)
+{
+    union geneve_sockaddr sa;
+    struct geneve_ftable_entry *fe;
+    int error;
+
+    GENEVE_DBG_ENTER("if_name: %s, tunnel: %s, mac: %02x:%02x:%02x:%02x:%02x:%02x, flags: %u",
+                    sc->geneve_ifp->if_xname, geneve_tun->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], flags);
+
+    if (flags & GENEVE_FE_FLAG_REMOTE && !gtep_addr) {
+        GENEVE_DBG_ERR("Fatal error in update geneve fwd.");
+        return EINVAL;
+    }
+
+    /*
+     * A forwarding entry for this MAC address might already exist. If
+     * so, update it, otherwise create a new one. We may have to upgrade
+     * the lock if we have to change or create an entry.
+     */
+    fe = geneve_ftable_entry_lookup(sc, mac);
+    if (fe != NULL) {
+        fe->expire = time_uptime + sc->geneve_ftable_timeout;
+
+        if (flags & GENEVE_FE_FLAG_DYNAMIC && !GENEVE_FE_IS_DYNAMIC(fe)) {  /*dynamic never override static*/
+            return 0;
+        }
+
+        if (flags & GENEVE_FE_FLAG_STATIC && GENEVE_FE_IS_DYNAMIC(fe)) {
+            fe->flags = flags;
+        }
+
+        if (flags & GENEVE_FE_FLAG_REMOTE && geneve_sockaddr_in_equal(&fe->raddr, gtep_addr)) {  /*remote and no change*/
+            return 0;
+        }
+
+        if (flags & GENEVE_FE_FLAG_LOCAL && fe->flags & GENEVE_FE_FLAG_LOCAL) /*local ifp never change*/
+            return 0;
+
+        if (flags & GENEVE_FE_FLAG_REMOTE) {
+            geneve_sockaddr_in_copy(&fe->raddr, gtep_addr);
+            fe->tunnel = geneve_tun;
+            fe->flags &= 0x0;
+            fe->flags = flags;
+        } else if (flags & GENEVE_FE_FLAG_LOCAL) {
+            memset(&fe->raddr, 0, sizeof(union geneve_sockaddr));
+            fe->tunnel = NULL;
+            fe->flags &= 0x0;
+            fe->flags = flags;
+            GENEVE_DBG_INFO("mac changed to local.");
+        }
+        return (0);
+    }
+
+    if (sc->geneve_ftable_cnt >= sc->geneve_ftable_max) {
+        sc->geneve_stat.geneve_ftable_nospace++;
+        GENEVE_DBG_ERR("no space in geneve fwd table.");
+        return ENOSPC;
+    }
+
+    fe = geneve_ftable_entry_alloc();
+    if (fe == NULL) {
+        sc->geneve_stat.geneve_ftable_alloc_fail++;
+        GENEVE_DBG_ERR("geneve fe allocate failed.");
+        return ENOMEM;
+    }
+        
+    if (flags & GENEVE_FE_FLAG_REMOTE) {
+        /*
+         *  The source port may be random, so always use the port of the
+         *  default destination address.
+         */
+        geneve_sockaddr_copy(&sa, gtep_addr);
+        sa.in4.sin_port = htons((uint16_t)gtep.geneve_port);
+        fe->tunnel = geneve_tun;
+    }
+    
+    geneve_ftable_entry_init(sc, fe, mac, &sa.sa, flags);
+
+    /* The prior lookup failed, so the insert should not. */
+    error = geneve_ftable_entry_insert(sc, fe);
+    if (error) {
+        sc->geneve_stat.geneve_ftable_insert_fail++;
+        GENEVE_DBG_ERR("ftable insert failed.");
+        geneve_ftable_entry_free(fe);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+geneve_ftable_update(struct geneve_softc *sc, const struct sockaddr *gtep_addr, struct geneve_tunnel *geneve_tun,
+                        const uint8_t *mac, uint32_t flags)
+{
+    struct rm_priotracker tracker;
+    GENEVE_DBG_ENTER("if_name: %s, tunnel: %s, mac: %02x:%02x:%02x:%02x:%02x:%02x, flags: %u",
+                    sc->geneve_ifp->if_xname, geneve_tun->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], flags);
+    return geneve_ftable_update_locked(sc, gtep_addr, geneve_tun, mac, &tracker, flags);
+}
+
+static int 
+geneve_create_ctx(struct geneve_softc *sc, int port_id)
+{
+    char geneve_veth_name[GENEVE_KNI_NAME_LEN];
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, port_id: %d", sc, sc->geneve_ifp->if_xname, port_id);
+
+    snprintf(geneve_veth_name, GENEVE_KNI_NAME_LEN, GENEVE_KNI_NAME_FMT, port_id);
+    
+    sc->dpdk_host_ctx = if_dpdk_create_geneve_ctx(geneve_veth_name, port_id);
+    if (sc->dpdk_host_ctx == NULL) {
+        GENEVE_DBG_ERR("Create %s failed: fail to alloc context", geneve_veth_name);
+        return -1;
+    }
+
+    printf("Create %s done\n", geneve_veth_name);
+
+    return 0;
+}
+
+static void 
+geneve_delete_ctx(int port_id)
+{
+    GENEVE_DBG_ENTER("port_id: %d", port_id);
+    if_dpdk_delete_geneve_ctx(port_id);
+}
+
+static void
+geneve_fakeaddr(struct geneve_softc *sc)
+{
+    /*
+     * Generate a non-multicast, locally administered address.
+     *
+     * BMV: Should we use the FreeBSD OUI range instead?
+     */
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+    arc4rand(sc->geneve_hwaddr, ETHER_ADDR_LEN, 1);
+    sc->geneve_hwaddr[0] &= ~1;
+    sc->geneve_hwaddr[0] |= 2;
+}
+
+static int
+geneve_sockaddr_cmp(const union geneve_sockaddr *addr, const struct sockaddr *sa)
+{
+    GENEVE_DBG_ENTER("addr: %p, sa: %p", addr, sa);
+    return (bcmp(&addr->sa, sa, addr->sa.sa_len));
+}
+
+static void
+geneve_sockaddr_copy(union geneve_sockaddr *addr, const struct sockaddr *sa)
+{
+    GENEVE_DBG_ENTER("addr: %p, sa: %p", addr, sa);
+
+    MPASS(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
+    bzero(addr, sizeof(*addr));
+
+    if (sa->sa_family == AF_INET) {
+        addr->in4 = *(const struct sockaddr_in *)sa;
+        addr->in4.sin_len = sizeof(struct sockaddr_in);
+    } else if (sa->sa_family == AF_INET6) {
+        addr->in6 = *(const struct sockaddr_in6 *)sa;
+        addr->in6.sin6_len = sizeof(struct sockaddr_in6);
+    }
+}
+
+static int
+geneve_sockaddr_in_equal(const union geneve_sockaddr *addr, const struct sockaddr *sa)
+{
+    int equal;
+
+    GENEVE_DBG_ENTER("addr: %p, sa: %p", addr, sa);
+ 
+    if (sa->sa_family == AF_INET) {
+        const struct in_addr *in4 = &(((const struct sockaddr_in *)sa)->sin_addr);
+        equal = (in4->s_addr == addr->in4.sin_addr.s_addr);
+    } else if (sa->sa_family == AF_INET6) {
+        const struct in6_addr *in6 = &(((const struct sockaddr_in6 *)sa)->sin6_addr);
+        equal = (IN6_ARE_ADDR_EQUAL(in6, &addr->in6.sin6_addr));
+    } else {
+        equal = 0;
+    }
+
+    return equal;
+}
+
+static void
+geneve_sockaddr_in_copy(union geneve_sockaddr *addr, const struct sockaddr *sa)
+{
+    GENEVE_DBG_ENTER("addr: %p, sa: %p", addr, sa);
+
+    MPASS(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
+
+    if (sa->sa_family == AF_INET) {
+        const struct in_addr *in4 = &(((const struct sockaddr_in *)sa)->sin_addr);
+        addr->in4.sin_family = AF_INET;
+        addr->in4.sin_len = sizeof(struct sockaddr_in);
+        addr->in4.sin_addr = *in4;
+    } else if (sa->sa_family == AF_INET6) {
+        const struct in6_addr *in6 = &(((const struct sockaddr_in6 *)sa)->sin6_addr);
+        addr->in6.sin6_family = AF_INET6;
+        addr->in6.sin6_len = sizeof(struct sockaddr_in6);
+        addr->in6.sin6_addr = *in6;
+    }
+}
+
+static int
+geneve_sockaddr_supported(const union geneve_sockaddr *addr, int unspec)
+{
+    const struct sockaddr *sa;
+    int supported;
+
+    GENEVE_DBG_ENTER("addr: %p, unspec: %d", addr, unspec);
+
+    sa = &addr->sa;
+    supported = 0;
+
+    if (sa->sa_family == AF_UNSPEC && unspec != 0) {
+        supported = 1;
+    } else if (sa->sa_family == AF_INET) {
+#ifdef INET
+        supported = 1;
+#endif
+    } else if (sa->sa_family == AF_INET6) {
+#ifdef INET6
+        supported = 1;
+#endif
+    }
+
+    return supported;
+}
+
+static int
+geneve_sockaddr_in_any(const union geneve_sockaddr *addr)
+{
+    const struct sockaddr *sa;
+    int any;
+
+    GENEVE_DBG_ENTER("addr: %p", addr);
+
+    sa = &addr->sa;
+
+    if (sa->sa_family == AF_INET) {
+        const struct in_addr *in4 = &(((const struct sockaddr_in *)sa)->sin_addr);
+        any = in4->s_addr == INADDR_ANY;
+    } else if (sa->sa_family == AF_INET6) {
+        const struct in6_addr *in6 = &(((const struct sockaddr_in6 *)sa)->sin6_addr);
+        any = IN6_IS_ADDR_UNSPECIFIED(in6);
+    } else
+        any = -1;
+
+    return any;
+}
+
+static int
+geneve_sockaddr_in_multicast(const union geneve_sockaddr *addr)
+{
+    const struct sockaddr *sa;
+    int mc;
+
+    GENEVE_DBG_ENTER("addr: %p", addr);
+
+    sa = &addr->sa;
+
+    if (sa->sa_family == AF_INET) {
+        const struct in_addr *in4 = &(((const struct sockaddr_in *)sa)->sin_addr);
+        mc = IN_MULTICAST(ntohl(in4->s_addr));
+    } else if (sa->sa_family == AF_INET6) {
+        const struct in6_addr *in6 = &(((const struct sockaddr_in6 *)sa)->sin6_addr);
+        mc = IN6_IS_ADDR_MULTICAST(in6);
+    } else
+        mc = -1;
+
+    return mc;
+}
+
+static int
+atcp_geneve_output(struct ifnet *ifp, struct mbuf *m)
+{
+    int error;
+
+    GENEVE_DBG_ENTER("if_name: %s, m: %p", ifp->if_xname, m);
+
+    error = (ifp->if_transmit)(ifp, m);
+    
+    return error;
+}
+
+static uint16_t
+geneve_pick_source_port(struct geneve_softc *sc, struct mbuf *m)
+{
+    int range;
+    uint32_t hash;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, m: %p", sc, sc->geneve_ifp->if_xname, m);
+
+    range = sc->geneve_max_port - sc->geneve_min_port + 1;
+
+    if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE && M_HASHTYPE_GET(m) != M_HASHTYPE_OPAQUE) {
+        hash = m->m_pkthdr.flowid;
+    } else {
+        hash = jenkins_hash(m->m_data, ETHER_HDR_LEN, sc->geneve_port_hash_key);
+    }
+
+    return (sc->geneve_min_port + (hash % range));
+}
+
+static void
+geneve_encap_header(struct geneve_softc *sc, struct geneve_tunnel *geneve_tun, struct mbuf *m, int ipoff,
+                    uint16_t srcport, uint16_t dstport, int is_ipv6)
+{
+    struct geneve_udphdr *hdr;
+    struct udphdr *udph;
+    struct geneve_header *gh;
+    struct ip6_hdr *ip6;
+    int len;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, tunnel: %s, m: %p, ipoff: %d, srcport: %d, dstport: %d, is_ipv6: %d",
+                        sc, sc->geneve_ifp->if_xname, geneve_tun->name, m, ipoff, ntohs(srcport), ntohs(dstport), is_ipv6);
+
+    len = m->m_pkthdr.len - ipoff;
+    MPASS(len >= sizeof(struct geneve_udphdr));
+    hdr = mtodo(m, ipoff);
+
+    udph = &hdr->uhdr;
+    udph->uh_sport = srcport;
+    udph->uh_dport = dstport;
+    udph->uh_ulen = htons(len);
+    udph->uh_sum = 0;
+
+    gh = &hdr->ghdr;
+    gh->ver = htons(GENEVE_VER);
+    gh->opt_len = 0;
+    gh->oam = 0;
+    gh->critical = 0;
+    gh->rsvd = 0;
+    gh->proto_type = htons(ETHERTYPE_TRANSETHER);
+    gh->vni = htonl(sc->geneve_vni << GENEVE_HDR_VNI_SHIFT);
+
+    if (is_ipv6) {
+        ip6 = mtod(m, struct ip6_hdr *);
+        if (m->m_pkthdr.len > geneve_tun->ifp->if_mtu) {
+            /*hardware checksum may work abormal for UDP if IP fragment happened*/
+            clickudp6_udp_cksum_sw(m, IPPROTO_UDP, sizeof(struct ip6_hdr), ntohs(ip6->ip6_plen), ip6, udph, geneve_tun->ifp);
+        } else {
+            clickudp6_cksum(m, IPPROTO_UDP, sizeof(struct ip6_hdr), ntohs(ip6->ip6_plen), ip6, udph, geneve_tun->ifp);
+        }
+    } else {
+        if (m->m_pkthdr.len > geneve_tun->ifp->if_mtu) {
+            /*hardware checksum may work abormal for UDP if IP fragment happened*/
+            clickudp_udp_cksum_sw(m, geneve_tun->ifp);
+        } else {
+            clickudp_cksum(m, geneve_tun->ifp);
+        }
+    }
+}
+
+static int
+geneve_encap4_send(struct geneve_softc *sc, struct geneve_tunnel *geneve_tun, 
+                    const union geneve_sockaddr *geneve_sa, struct mbuf *m, int multicast)
+{
+#ifdef INET
+    struct ifnet *ifp;
+    struct ip *ip;
+    struct in_addr srcaddr, dstaddr;
+    uint16_t srcport, dstport;
+    int len, error = 0;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, geneve_tun: %s, geneve_sa: %p, m: %p, multicast: %d",
+                        sc, sc->geneve_ifp->if_xname, geneve_tun->name, geneve_sa, m, multicast);
+
+    if (!geneve_tun) {
+        GENEVE_DBG_ERR("no geneve tunnel, if_name: %s, vni: %d.", sc->geneve_ifp->if_xname, sc->geneve_vni);
+        goto fail;
+    }
+
+    ifp = sc->geneve_ifp;
+    srcaddr.s_addr = geneve_tun->src_addr.in4.sin_addr.s_addr;
+
+    srcport = geneve_pick_source_port(sc, m);
+    dstport = htons((uint16_t)gtep.geneve_port);
+    dstaddr = geneve_sa->in4.sin_addr;
+
+    M_PREPEND(m, sizeof(struct ip) + sizeof(struct geneve_udphdr), M_NOWAIT);
+    if (!m) {
+        GENEVE_DBG_ERR("prepend mbuf failed.");
+        return ENOBUFS;
+    }
+
+    len = m->m_pkthdr.len;
+
+    ip = mtod(m, struct ip *);
+    ip->ip_v = 0x4;
+    ip->ip_hl = 0x5; /* 20 >> 2 */
+    ip->ip_tos = 0;
+    ip->ip_len = htons(len);
+    ip->ip_off = 0;
+    ip->ip_ttl = sc->geneve_ttl;
+    ip->ip_p = IPPROTO_UDP;
+    ip->ip_sum = 0;
+    ip->ip_src = srcaddr;
+    ip->ip_dst = dstaddr;
+
+    geneve_encap_header(sc, geneve_tun, m, sizeof(struct ip), srcport, dstport, 0);
+
+    m->m_flags &= ~(M_MCAST | M_BCAST);
+
+    sc->geneve_stat.geneve_tun_pkt_out++;
+
+    if (IS_ATCP() && !multicast) {
+        GENEVE_DBG_INFO("atcp sending unicast out via ip_output");
+        ip_output(m, NULL, NULL, 0, NULL, NULL);
+    } else if (!IS_ATCP() && !multicast) {
+        GENEVE_DBG_INFO("Non atcp sending unicast out via ip_output");
+        ip_output(m, NULL, NULL, 0, NULL, NULL);
+    } else {
+        GENEVE_DBG_INFO("Non atcp sending multicast out via ip_output");
+        ip_output(m, NULL, NULL, 0, geneve_tun->im4o, NULL);
+    }
+
+    return error;
+
+fail:
+    if (m) {
+        m_freem(m);
+    }
+
+    return -1;
+
+#else
+    m_freem(m);
+    return ENOTSUP;
+#endif
+}
+
+static int
+geneve_encap6_send(struct geneve_softc *sc, struct geneve_tunnel *geneve_tun, 
+                    const union geneve_sockaddr *geneve_sa, struct mbuf *m, int multicast)
+{
+#ifdef INET6
+    struct ifnet *ifp;
+    struct ip6_hdr *ip6;
+    const struct in6_addr *srcaddr, *dstaddr;
+    uint16_t srcport, dstport;
+    int len, error;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, geneve_tun: %s, geneve_sa: %p, m: %p, multicast: %d",
+                        sc, sc->geneve_ifp->if_xname, geneve_tun->name, geneve_sa, m, multicast);
+
+    if (!geneve_tun) {
+        GENEVE_DBG_ERR("no geneve tunnel, if_name: %s, vni %d.", sc->geneve_ifp->if_xname, sc->geneve_vni);
+        if (m) {
+            m_freem(m);
+        }
+        return -1;
+    }
+
+    ifp = sc->geneve_ifp;
+    srcaddr = &geneve_tun->src_addr.in6.sin6_addr;
+    srcport = geneve_pick_source_port(sc, m);
+    dstaddr = &geneve_sa->in6.sin6_addr;
+    dstport = htons((uint16_t)gtep.geneve_port);
+
+    M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct geneve_udphdr), M_NOWAIT);
+    if (!m) {
+        return ENOBUFS;
+    }
+
+    len = m->m_pkthdr.len - sizeof(struct ip6_hdr);
+
+    ip6 = mtod(m, struct ip6_hdr *);
+    ip6->ip6_flow = 0;    /* BMV: Keep in forwarding entry? */
+    ip6->ip6_vfc  = IPV6_VERSION;
+    ip6->ip6_plen = htons(len);
+    ip6->ip6_nxt  = IPPROTO_UDP;
+    ip6->ip6_hlim = sc->geneve_ttl;
+    ip6->ip6_src  = *srcaddr;
+    ip6->ip6_dst  = *dstaddr;
+
+    geneve_encap_header(sc, geneve_tun, m, sizeof(struct ip6_hdr), srcport, dstport, 1);
+
+    m->m_flags &= ~(M_MCAST | M_BCAST);
+
+    if (multicast) {
+        GENEVE_DBG_INFO("atcp sending multicast out via ip6_output");
+        error = ip6_output(m, NULL, NULL, 0, geneve_tun->im6o, NULL, NULL);
+    } else {
+        GENEVE_DBG_INFO("atcp sending unicast out via ip6_output");
+        error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+    }
+
+    return error;
+
+#else
+    m_freem(m);
+    return ENOTSUP;
+#endif
+}
+
+static int
+geneve_transmit(struct ifnet *ifp, struct mbuf *m)
+{
+    struct ether_header *eh;
+    struct geneve_softc *sc;
+    struct geneve_ftable_entry *fe = NULL;
+    union geneve_sockaddr geneve_sa;
+    int isipv4, error = 0, multicast = 0;
+
+    GENEVE_DBG_ENTER("ifp: %p, if_name: %s, m: %p", ifp, ifp->if_xname, m);
+
+    sc = ifp->if_softc;
+    eh = mtod(m, struct ether_header *);
+
+    if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+        m_freem(m);
+        return ENETDOWN;
+    }
+
+    if ((m->m_flags & (M_BCAST | M_MCAST)) == 0) {
+        fe = geneve_ftable_entry_lookup(sc, eh->ether_dhost);
+    }
+
+    if(!fe) {
+        int i;
+        struct mbuf *n;
+        struct geneve_tunnel *geneve_tun = NULL;
+
+        GENEVE_ACQUIRE(sc);
+
+        for (i = 0; i < GENEVE_VNI_MAX_TUNNEL; i++) {
+            geneve_tun = sc->geneve_tunl_tbl[i];
+
+            if (geneve_tun) {
+                GENEVE_DBG_INFO("if_name: %s, vni: %d, flooding tunnel: %s", 
+                                sc->geneve_ifp->if_xname, sc->geneve_vni, geneve_tun->name);
+
+                if (!(n = m_dup(m, M_NOWAIT))) {
+                    GENEVE_DBG_ERR("dup mbuf failed");
+                    continue;
+                }
+
+                geneve_sockaddr_copy(&geneve_sa, &geneve_tun->dst_addr.sa);
+
+                isipv4 = (GENEVE_SOCKADDR_IS_IPV4(&geneve_sa) != 0);
+
+                if (geneve_sockaddr_in_multicast(&geneve_sa) != 0) {
+                    multicast = 1;
+                } else {
+                    multicast = 0;
+                }
+
+                /* For Unicast, lookup eroute and send out */
+                if (isipv4) {
+                    error = geneve_encap4_send(sc, geneve_tun, &geneve_sa, n, multicast);
+                } else {
+                    error = geneve_encap6_send(sc, geneve_tun, &geneve_sa, n, multicast);
+                }
+
+                if (error) {
+                    GENEVE_DBG_ERR("error in geneve transmit [%d].\n", error);
+                    break;
+                }
+            }
+        }
+
+        if (sc->geneve_gw_ifp) {
+            sc->geneve_stat.geneve_local_pkt_out++;
+            GENEVE_DBG_INFO("flooding to local associated vlan: %s, vni: %d", 
+                            sc->geneve_gw_ifp->if_xname, sc->geneve_vni);
+            
+            if (IS_ATCP()) {
+                error = sc->geneve_gw_ifp->atcp_if_output(sc->geneve_gw_ifp, m);
+            } else {
+                error = sc->geneve_gw_ifp->if_transmit(sc->geneve_gw_ifp, m);
+            }
+
+            if (error) {
+                GENEVE_DBG_ERR("flood to local gw vlan failed, local vlan: %s, vni: %d.", 
+                                sc->geneve_gw_ifp->if_xname, sc->geneve_vni);
+            }
+        }
+
+        geneve_release(sc);
+
+        return error;
+    }
+
+    /* DST is local, atcp_if_output. */
+    if (fe->flags & GENEVE_FE_FLAG_LOCAL) {
+        if (sc->geneve_gw_ifp) {
+            sc->geneve_stat.geneve_local_pkt_out++;
+            GENEVE_DBG_INFO("forwarding to local associated vlan: %s, vni: %d", 
+                            sc->geneve_gw_ifp->if_xname, sc->geneve_vni);
+
+            error = sc->geneve_gw_ifp->atcp_if_output(sc->geneve_gw_ifp, m);
+            if (error) {
+                GENEVE_DBG_ERR("forward to local gw vlan failed, local vlan: %s, vni: %d.", 
+                                sc->geneve_gw_ifp->if_xname, sc->geneve_vni);
+            }
+        }
+        return error;
+    }
+
+    geneve_sockaddr_copy(&geneve_sa, &fe->raddr.sa);
+
+    GENEVE_DBG_INFO("forwarding to tunnel %s", fe->tunnel->name);
+
+    isipv4 = (GENEVE_SOCKADDR_IS_IPV4(&geneve_sa) != 0);
+
+    /* is this logic meaningful??? */
+    if (geneve_sockaddr_in_multicast(&geneve_sa) != 0) {
+        multicast = 1;
+        GENEVE_DBG_INFO("Strange to come here. find fe with multicast dst IP, will panic....");
+    } else {
+        multicast = 0;
+    }
+
+    GENEVE_ACQUIRE(sc);
+
+    if (isipv4) {
+        error = geneve_encap4_send(sc, fe->tunnel, &geneve_sa, m, multicast);
+    } else {
+        error = geneve_encap6_send(sc, fe->tunnel, &geneve_sa, m, multicast);
+    }
+
+    geneve_release(sc);
+
+    return error;
+}
+
+static void
+geneve_qflush(struct ifnet *ifp __unused)
+{
+}
+
+static void
+geneve_set_default_config(struct geneve_softc *sc)
+{
+    GENEVE_DBG_ENTER("sc: %p", sc);
+
+    sc->geneve_flags |= GENEVE_FLAG_LEARN;
+    sc->geneve_vni = GENEVE_VNI_MAX;
+    sc->geneve_ttl = IPDEFTTL;
+
+    sc->geneve_src_addr.in4.sin_port = htons(GENEVE_DEFAULT_PORT);
+    sc->geneve_dst_addr.in4.sin_port = htons(GENEVE_DEFAULT_PORT);
+
+    sc->geneve_min_port = V_ipport_firstauto;
+    sc->geneve_max_port = V_ipport_lastauto;
+
+    sc->geneve_ftable_max     = GENEVE_FTABLE_MAX;
+    sc->geneve_ftable_timeout = GENEVE_FTABLE_TIMEOUT;
+}
+
+static void
+geneve_timer(void *xsc)
+{
+    struct geneve_softc *sc;
+
+    GENEVE_DBG_ENTER("xsc: %p", xsc);
+
+    sc = xsc;
+
+    geneve_ftable_expire(sc);
+    callout_schedule(&sc->geneve_callout, geneve_ftable_prune_period * hz);
+}
+
+static struct geneve_softc *
+geneve_lookup_softc_locked(uint32_t vni)
+{
+    struct geneve_softc *sc;
+    uint32_t hash;
+
+    GENEVE_DBG_ENTER("vni: %d", vni);
+
+    GENEVE_GTEP_LOCK_ASSERT(gtep);
+    hash = GENEVE_SO_VNI_HASH(vni);
+
+    LIST_FOREACH(sc, &gtep.vni_hash[hash], geneve_entry) {
+        if (sc->geneve_vni == vni) {
+            GENEVE_ACQUIRE(sc);
+            break;
+        }
+    }
+
+    return sc;
+}
+
+static struct geneve_softc* 
+geneve_lookup_softc(uint32_t vni)
+{
+    struct geneve_softc *sc = NULL;
+    uint32_t hash;
+
+    GENEVE_DBG_ENTER("vni: %d", vni);
+
+    hash = GENEVE_SO_VNI_HASH(vni);
+
+    LIST_FOREACH(sc, &gtep.vni_hash[hash], geneve_list_entry) {
+        if (sc->geneve_vni == vni) {
+            GENEVE_ACQUIRE(sc);
+            break;
+        }
+    }
+
+    return sc;
+}
+
+static int
+geneve_insert_softc(struct geneve_softc *sc)
+{
+    struct geneve_softc *gsc;
+    uint32_t vni, hash;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, vni: %d", sc, sc->geneve_ifp->if_xname, sc->geneve_vni);
+
+    vni = sc->geneve_vni;
+    hash = GENEVE_SO_VNI_HASH(vni);
+
+    GENEVE_GTEP_WLOCK(gtep);
+
+    gsc = geneve_lookup_softc_locked(vni);
+    if (gsc != NULL) {
+        GENEVE_GTEP_WUNLOCK(gtep);
+        geneve_release(gsc);
+        GENEVE_DBG_ERR("geneve aready in the hash list.");
+        return EEXIST;
+    }
+
+    GENEVE_ACQUIRE(sc);
+    LIST_INSERT_HEAD(&gtep.vni_hash[hash], sc, geneve_entry);
+    GENEVE_GTEP_WUNLOCK(gtep);
+
+    return 0;
+}
+
+static void
+geneve_remove_softc(struct geneve_softc *sc)
+{
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+    GENEVE_GTEP_WLOCK(gtep);
+    LIST_REMOVE(sc, geneve_entry);
+    GENEVE_GTEP_WUNLOCK(gtep);
+    geneve_release(sc);
+}
+
+static void
+geneve_setup_interface(struct geneve_softc *sc)
+{
+    struct ifnet *ifp;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+
+    ifp = sc->geneve_ifp;
+    ifp->if_hdrlen = ETHER_HDR_LEN + sizeof(struct geneve_udphdr);
+
+    if (GENEVE_SOCKADDR_IS_IPV4(&sc->geneve_dst_addr) != 0) {
+        ifp->if_hdrlen += sizeof(struct ip);
+    }
+    else if (GENEVE_SOCKADDR_IS_IPV6(&sc->geneve_dst_addr) != 0) {
+        ifp->if_hdrlen += sizeof(struct ip6_hdr);
+    }
+}
+
+static void
+geneve_init_complete(struct geneve_softc *sc)
+{
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+    sc->geneve_flags &= ~GENEVE_FLAG_INIT;
+    wakeup(sc);
+}
+
+static void
+geneve_init(void *xsc)
+{
+    static const uint8_t empty_mac[ETHER_ADDR_LEN];
+    struct geneve_softc *sc;
+    struct ifnet *ifp;
+
+    GENEVE_DBG_ENTER("xsc: %p", xsc);
+
+    sc = xsc;
+    ifp = sc->geneve_ifp;
+
+    if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+        return;
+    }
+    sc->geneve_flags |= GENEVE_FLAG_INIT;
+
+    geneve_setup_interface(sc);
+
+    if(geneve_insert_softc(sc) != 0) {
+        goto out;
+    }
+
+    ifp->if_drv_flags |= IFF_DRV_RUNNING;
+    callout_reset(&sc->geneve_callout, geneve_ftable_prune_period * hz, geneve_timer, sc);
+
+out:
+    geneve_init_complete(sc);
+}
+
+static void
+geneve_release(struct geneve_softc *sc)
+{
+    /*
+     * The softc may be destroyed as soon as we release our reference,
+     * so we cannot serialize the wakeup with the softc lock. We use a
+     * timeout in our sleeps so a missed wakeup is unfortunate but not
+     * fatal.
+     */
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+    if (GENEVE_RELEASE(sc) != 0) {
+        wakeup(sc);
+    }
+}
+
+static void
+geneve_teardown_wait(struct geneve_softc *sc)
+{
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+    if (sc->geneve_flags & GENEVE_FLAG_TEARDOWN) {
+        GENEVE_DBG_INFO("geneve is under tearing down. vni: %d\n", sc->geneve_vni);
+    }
+}
+
+static void
+geneve_teardown_complete(struct geneve_softc *sc)
+{
+    GENEVE_DBG_ENTER("sc: %p, if_xname: %s", sc, sc->geneve_ifp->if_xname);
+    sc->geneve_flags &= ~GENEVE_FLAG_TEARDOWN;
+    wakeup(sc);
+}
+
+static void
+geneve_teardown_locked(struct geneve_softc *sc)
+{
+    struct ifnet *ifp;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+
+    ifp = sc->geneve_ifp;
+
+    MPASS(sc->geneve_flags & GENEVE_FLAG_TEARDOWN);
+
+    ifp->if_flags &= ~IFF_UP;
+    ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+    callout_stop(&sc->geneve_callout);
+
+    geneve_remove_softc(sc);
+
+    callout_drain(&sc->geneve_callout);
+
+    geneve_teardown_complete(sc);
+}
+
+static void
+geneve_teardown(struct geneve_softc *sc)
+{
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s", sc, sc->geneve_ifp->if_xname);
+
+    if (sc->geneve_flags & GENEVE_FLAG_TEARDOWN) {
+        geneve_teardown_wait(sc);
+        return;
+    }
+    sc->geneve_flags |= GENEVE_FLAG_TEARDOWN;
+    geneve_teardown_locked(sc);
+}
+
+static int
+geneve_clone_create(struct if_clone *ifc, int unit, caddr_t params)
+{
+    struct geneve_softc *sc;
+    struct ifnet *ifp;
+
+    GENEVE_DBG_ENTER("ifc: %p, unit: %d", ifc, unit);
+
+    sc = malloc(sizeof(struct geneve_softc), M_GENEVE, M_WAITOK | M_ZERO);
+    sc->geneve_unit = unit;
+
+    geneve_set_default_config(sc);
+
+    ifp = if_alloc(IFT_ETHER);
+    if (ifp == NULL) {
+        free(sc, M_GENEVE);
+        return ENOSPC;
+    }
+
+    geneve_ftable_init(sc);
+
+    mtx_init(&sc->geneve_mtx, "geneve_mtx", NULL, MTX_DEF);
+    callout_init_mtx(&sc->geneve_callout, &sc->geneve_mtx, 0);
+    rm_init(&sc->geneve_lock, "geneverm");
+
+    sc->geneve_ifp = ifp;
+    ifp->if_softc = sc;
+    if_initname(ifp, geneve_name, unit);
+    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+    ifp->if_init = geneve_init;
+    ifp->if_ioctl = geneve_ioctl;
+
+    ifp->atcp_if_output = atcp_geneve_output;
+    ifp->if_transmit = geneve_transmit;
+    ifp->if_qflush = geneve_qflush;
+
+    geneve_fakeaddr(sc);  /*ETH ADDR*/
+    ether_ifattach(ifp, sc->geneve_hwaddr);
+
+    ifp->if_baudrate = 0;
+    ifp->if_hdrlen = 0;
+    ifp->if_mode = IF_MODE_GENEVE;
+    ifp->if_link_state = LINK_STATE_UP;     /* GENEVE interface should always be UP */
+
+    geneve_softc_arr[ifp->if_dunit] = sc;
+    
+    if (geneve_create_ctx(sc, ifp->if_dunit) != 0) {
+        ether_ifdetach(ifp);
+        if_free(ifp);
+
+        geneve_ftable_fini(sc);
+        rm_destroy(&sc->geneve_lock);
+        mtx_destroy(&sc->geneve_mtx);
+        free(sc, M_GENEVE);
+        geneve_softc_arr[ifp->if_dunit] = NULL;
+
+        return ENOSPC;
+    }
+    
+    LIST_INSERT_HEAD(&geneve_sc_list, sc, geneve_list_entry);
+
+    return 0;
+}
+
+static void
+geneve_clone_destroy(struct ifnet *ifp)
+{
+    struct geneve_softc *sc;
+    int unit;
+
+    GENEVE_DBG_ENTER("ifp: %p, if_name: %s", ifp, ifp->if_xname);
+
+    sc = ifp->if_softc;
+    unit = ifp->if_dunit;
+
+    geneve_delete_ctx(unit);
+
+    geneve_teardown(sc);
+
+    geneve_ftable_flush(sc, 1, NULL);
+
+    ether_ifdetach(ifp);
+    if_free(ifp);
+
+    /* free ftable and ftable locks */
+    geneve_ftable_fini(sc);
+    
+    rm_destroy(&sc->geneve_lock);
+
+    mtx_destroy(&sc->geneve_mtx);
+
+    LIST_REMOVE(sc, geneve_list_entry);
+    
+    free(sc, M_GENEVE);
+
+    geneve_softc_arr[unit] = NULL;
+}
+
+static void
+geneve_load(void)
+{
+    geneve_cloner = if_clone_simple(geneve_name, geneve_clone_create, geneve_clone_destroy, 0);
+    geneve_ftable_entry_zone = uma_zcreate("ftable_entry", sizeof(struct geneve_ftable_entry), 
+                                            NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+    gtep_init();
+}
+
+static void
+geneve_unload(void)
+{
+    if_clone_detach(geneve_cloner);
+    uma_zdestroy(geneve_ftable_entry_zone);
+}
+
+static int
+geneve_modevent(module_t mod, int type, void *unused)
+{
+    int error = 0;
+
+    switch (type) {
+        case MOD_LOAD:
+            geneve_load();
+            break;
+        case MOD_UNLOAD:
+            geneve_unload();
+            break;
+        default:
+            error = ENOTSUP;
+            break;
+    }
+
+    return error;
+}
+
+static moduledata_t geneve_mod = {
+    "if_geneve",
+    geneve_modevent,
+    0
+};
+
+DECLARE_MODULE(if_geneve, geneve_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+MODULE_VERSION(if_geneve, 1);
\ No newline at end of file
Index: /branches/rel_apv_10_7/usr/src/sys/net/if_var.h
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/net/if_var.h	(revision 39181)
+++ /branches/rel_apv_10_7/usr/src/sys/net/if_var.h	(working copy)
@@ -130,7 +130,8 @@
 	IF_MODE_BOND,
 	IF_MODE_VLAN,
 	IF_MODE_LOOPBACK,
-	IF_MODE_VXLAN
+	IF_MODE_VXLAN,
+	IF_MODE_GENEVE
 };
 #endif
 
@@ -315,6 +316,7 @@
 	void	*if_bridge;		/* bridge glue */
 
 	int vxlan_vni; /*vxlan_support*/
+	int geneve_vni; /* geneve support */
 
 	struct	label *if_label;	/* interface MAC label */
 
