Index: /branches/rel_apv_10_7/usr/click/lib/libip/ip.h
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libip/ip.h	(revision 39382)
+++ /branches/rel_apv_10_7/usr/click/lib/libip/ip.h	(working copy)
@@ -46,7 +46,7 @@
 
 /* geneve support */
 #define MAX_GENEVE            (2048)
-#define MIN_GENEVE_VNI        1
+#define MIN_GENEVE_VNI        0
 #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 */
Index: /branches/rel_apv_10_7/usr/click/lib/libip/sip.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libip/sip.c	(revision 39382)
+++ /branches/rel_apv_10_7/usr/click/lib/libip/sip.c	(working copy)
@@ -8602,7 +8602,7 @@
 	}
 
 	for ( i = 0; i < MAX_GENEVE; ++i) {
-		if (geneve_p[i].vni == 0)
+		if (geneve_p[i].ifname == '\0')
 			continue;
 		if (geneve_p[i].ip32) {
 			addr.s_addr = geneve_p[i].ip32;
@@ -15358,7 +15358,7 @@
 		if (getgeneveif_num(ifnum, &geneve) != 0) {
 			return;
 		}
-		if (geneve.vni == 0) {
+		if (geneve.ifname[0] == '\0') {
 			return;
 		}
 	} else if (type == SHOW_INTF_BOND) {
@@ -28433,7 +28433,8 @@
 
     if (geneve && !retval) {
         for (i = 0; i < MAX_GENEVE; i++) {
-            if (vni == geneve[i].vni) {
+            if ((vni != 0 && vni == geneve[i].vni) || 
+                (vni = 0 && strlen(geneve[i].ifname))) {
                 retval = geneve[i].ifname;
                 sprintf(ifname ,"The VNI number is already used by the GENEVE interface '%s'.\n", retval);
                 retval = ifname;
@@ -28444,7 +28445,7 @@
     }
 
     if (geneve) {
-        shmdt(geneve);  
+        shmdt(geneve);
     }
 
     return retval;
@@ -28603,7 +28604,7 @@
     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);
+    shm_geneve_tunid = shmget(GENEVE_TUN_SHM_KEY, sizeof(geneve_tun_t) * MAX_GENEVE_TUNNEL, IPC_CREAT | SHM_W | SHM_R);
     if (shm_geneve_tunid < 0) {
         printf("GENEVE: shmget error, return %d.\n", shm_geneve_tunid);
         return NULL;
@@ -29197,6 +29198,7 @@
     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);
+            reset_global_geneve_tunnel_config(i);
             break;
         }
     }
@@ -29205,8 +29207,6 @@
         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);
@@ -29238,6 +29238,7 @@
 
     gnv_tun = get_global_geneve_tunnel_config();
     if (!gnv_tun) {
+        shmdt(geneve_p);
         return GENEVE_ERROR;
     }
 
@@ -29359,8 +29360,7 @@
     }
 
     /*lookup vlan*/
-    shm_vlan_id = shmget(VLAN_SHM_KEY, sizeof(vlan_ip_t) * MAX_VLAN,
-    IPC_CREAT | SHM_W | SHM_R);
+    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");
@@ -29420,10 +29420,9 @@
     }
 
     for (i = 0; i < MAX_GENEVE; ++i) {
-        if (geneve_p[i].vni == 0) {
-            continue;
+        if (strlen(geneve_p[i].ifname)) {
+            printf("geneve interface \"%s\" %d\n", geneve_p[i].ifname, geneve_p[i].vni);
         }
-        printf("geneve interface \"%s\" %d\n", geneve_p[i].ifname, geneve_p[i].vni);
     }
 
     shmdt(geneve_p);
@@ -29474,12 +29473,13 @@
 
     gnv_tun = get_global_geneve_tunnel_config();
     if (!gnv_tun) {
-        return GENEVE_ERROR;        
+        shmdt(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) {
+            if (strlen(geneve_p[i].ifname) == 0) {
                 continue;
             }
             for (j = 0; j < GENEVE_VNI_MAX_TUNNEL; ++j) {
@@ -29522,7 +29522,7 @@
 	}
 
 	for (i = 0; i < MAX_GENEVE; ++i) {
-		if (geneve_p[i].vni ==0) {
+		if (strlen(geneve_p[i].ifname) == 0) {
 			continue;
 		}
 		ret = clear_geneve_forwarding_kern(geneve_p[i].vni);
@@ -29548,7 +29548,7 @@
 
     if (NULL == geneve_name || geneve_name[0] == '\0') {
         for (i = 0; i < MAX_GENEVE; ++i) {
-            if (geneve_p[i].vni == 0) {
+            if (strlen(geneve_p[i].ifname) == 0) {
                 continue;
             }
             if (geneve_p[i].geneve_gw_if[0] != '\0') {
@@ -29624,7 +29624,7 @@
     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);
+        printf("GENEVE: vni %d is invalid, it should be in range[%d, %d].\n", vni, MIN_GENEVE_VNI, MAX_GENEVE_VNI);
         return GENEVE_ERROR;
     }
 
@@ -29632,9 +29632,9 @@
     if(!geneve_p) {
         return GENEVE_ERROR;
     }
-    
+
     for (i = 0; i < MAX_GENEVE; ++i) {
-        if (geneve_p[i].vni == vni) {
+        if (strlen(geneve_p[i].ifname) && geneve_p[i].vni == vni) {
             ret = show_geneve_forwarding_kern(vni, mac, geneve_p[i].geneve_gw_if);
             shmdt(geneve_p);
             return ret;
@@ -29673,12 +29673,13 @@
 
     gnv_tun = get_global_geneve_tunnel_config();
     if (!gnv_tun) {
-        return GENEVE_ERROR;        
+        shmdt(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) {
+            if (strlen(geneve_p[i].ifname) == 0) {
                 continue;
             }
             for (j = 0; j < GENEVE_VNI_MAX_TUNNEL; ++j) {
@@ -29688,6 +29689,8 @@
                     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");
+                        shmdt(geneve_p);
+                        shmdt(gnv_tun);
                         return ret;
                     }
                     geneve_p[i].geneve_tun[j] = MAX_GENEVE_TUNNEL;
@@ -29707,6 +29710,8 @@
                     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");
+                        shmdt(geneve_p);
+                        shmdt(gnv_tun);
                         return ret;
                     }
                     geneve_p[i].geneve_tun[j] = MAX_GENEVE_TUNNEL;
@@ -29791,6 +29796,7 @@
 
     for (i = 0; i < MAX_GENEVE_TUNNEL; i++) {
         if (geneve_tun[i].valid == 0) {
+            memset(&geneve_tun[i], 0, sizeof(geneve_tun_t));
             continue;
         }
 
@@ -29800,7 +29806,7 @@
             shmdt(geneve_tun);
             return ret;
         }
-        memset(&geneve_tun[i], 0, sizeof(geneve_tun_t));    
+        memset(&geneve_tun[i], 0, sizeof(geneve_tun_t));
     }
 
     shmdt(geneve_tun);
@@ -29819,7 +29825,7 @@
     }
 
     for (i = 0; i < MAX_GENEVE; i++) {
-        if (geneve_p[i].vni) {
+        if (strlen(geneve_p[i].ifname)) {
             if (geneve_p[i].geneve_gw_if[0]!='\0') {
                 shmdt(geneve_p);
                 printf("Please remove geneve associate first.\n");
@@ -29880,6 +29886,7 @@
 
     geneve_tun = get_global_geneve_tunnel_config();
     if (!geneve_tun) {
+        shmdt(geneve_p);
         return NULL;
     }
 
@@ -29907,7 +29914,7 @@
     }
 
     for (i = 0; i < MAX_GENEVE; i++) {
-        if (geneve_p[i].vni == 0) {
+        if (strlen(geneve_p[i].ifname) == 0) {
             continue;
         }
 
Index: /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm	(revision 39382)
+++ /branches/rel_apv_10_7/usr/click/lib/libparser/commands.pm	(working copy)
@@ -43489,7 +43489,7 @@
 							},
 							{
 								type => "U32",
-								help_string => "VNI number",
+								help_string => "VNI number (0 is for AWS use)",
 								optional => "NO",
 							}
 						]
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 39382)
+++ /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_udp.c	(working copy)
@@ -931,11 +931,12 @@
 	struct geneve_header *gh, genevehdr;
 	uint32_t vni;
 	int hdr_len;
-
-	M_ASSERTPKTHDR(m);
+	int ver, opt_len;
 
 	GENEVE_DBG_ENTER("m: %p, isipv6: %d, ip: %p, ip6: %p, udp: %p", m, isipv6, ip, ip6, udp);
 
+	M_ASSERTPKTHDR(m);
+
 	if (isipv6) {
 		hdr_len = sizeof(struct ip6_hdr) + sizeof(struct udphdr);
 	} else {
@@ -953,18 +954,40 @@
 		gh = mtodo(m, hdr_len);
 	}
 
-	if (gh->ver != htons(GENEVE_VER) ||
-		gh->vni & ~htonl(GENEVE_VNI_MASK) ||
-		gh->proto_type != htons(ETHERTYPE_TRANSETHER)) {
+	ver = GENEVE_HEADER_GET_VER(gh);
+	opt_len = GENEVE_HEADER_GET_OPT_LEN(gh);
+	vni = GENEVE_HEADER_GET_VNI(gh);
+
+	if (ver != GENEVE_VER || opt_len > GENEVE_HDR_OPT_MAX_LEN || (vni < GENEVE_VNI_MIN || vni > GENEVE_VNI_MAX)) {
 		goto out;
 	}
 
-	vni = ntohl(gh->vni) >> GENEVE_HDR_VNI_SHIFT;
+	if (vni == AWS_GENEVE_VNI) {
+		uint8_t vpec_id[AWS_GENEVE_OPTION_VPCE_ID_LEN];
+		uint8_t attachment_id[AWS_GENEVE_OPTION_ATTACHMENT_ID_LEN];
+		uint8_t flow_cookie[AWS_GENEVE_OPTION_FLOW_COOKIE_LEN];
 
-	/* Adjust to the start of the inner Ethernet frame. */
-	m_adj(m, hdr_len + sizeof(struct geneve_header));
+		/* Adjust to the start of the geneve options frame. */
+		m_adj(m, hdr_len + sizeof(struct geneve_header));
 
-	geneve_learn_fwd(vni, m, ip, ip6, isipv6);
+		/* Parse AWS geneve options */
+		if (geneve_options_parser_for_aws(m, opt_len, vpec_id, attachment_id, flow_cookie)) {
+			GENEVE_DBG_ERR("Parse option failed");
+			goto out;
+		}
+
+		/* Adjust to the start of the inner frame. */
+		m_adj(m, opt_len);
+
+		/* Learn and forward packet based on AWS logic */
+		geneve_learn_fwd_for_aws(vpec_id, attachment_id, flow_cookie, m, ip, ip6, isipv6);
+	} else {
+		/* Adjust to the start of the inner Ethernet frame. */
+		m_adj(m, hdr_len + sizeof(struct geneve_header) + opt_len);
+
+		/* Learn and forward packet */
+		geneve_learn_fwd(vni, m, ip, ip6, isipv6);
+	}
 
 	return;
 
@@ -1151,7 +1174,7 @@
 	}
 
 	/* geneve process */
-	if (geneve_enable && (geneve_port == ntohs(udp->uh_dport))) {
+	if (geneve_enable && (geneve_port == ntohs(udp->uh_dport) || GENEVE_DEFAULT_PORT == ntohs(udp->uh_dport))) {
 		clicktcp_geneve_input(m, isipv6, ip, ip6, udp);
 		if (pcb != NULL) {
 			clickudp_cleanup_pcb(pcb);
Index: /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_var.h
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_var.h	(revision 39382)
+++ /branches/rel_apv_10_7/usr/src/sys/click/netinet/click_var.h	(working copy)
@@ -58,6 +58,7 @@
 #include <click/netinet/click_pcb.h>
 #include <click/sys/click_adapter.h>
 #include <net/if_llatbl.h>
+#include <net/if_geneve.h>
 #include <netinet/in_var.h>
 #include <click/netinet/click_segment.h>
 
@@ -1409,10 +1410,15 @@
 /* end bug 57710  chenhy  2015-7-28 */
 
 extern int llb_stat_enable;
+extern int geneve_aws_enable;
 
 /* IF_OUTPUT() is only for ipv4 */
 #define IF_OUTPUT(eroute_rule, m) do {	  \
 		struct route ro; \
+		if (geneve_aws_enable && m_tag_locate(m, MTAG_COOKIE_GENEVE, MTAG_GENEVE_AWS_OPTS, NULL)) { \
+			geneve_transmit_for_aws(m); \
+			break; \
+		} \
 		if ((eroute_rule)->flags & ARTF_BRROUTE) {	\
 			bridge_output_app(ERT_IFP(eroute_rule), m, ERT_GATEWAY(eroute_rule), NULL);	\
 			break;	\
Index: /branches/rel_apv_10_7/usr/src/sys/click/netinet6/click6_input.c
===================================================================
--- /branches/rel_apv_10_7/usr/src/sys/click/netinet6/click6_input.c	(revision 39382)
+++ /branches/rel_apv_10_7/usr/src/sys/click/netinet6/click6_input.c	(working copy)
@@ -182,6 +182,7 @@
 extern int input_hwcksum_ipv6;
 extern int triangle_flag;
 extern int llb_stat_enable;
+extern int geneve_aws_enable;
 extern int vipstats;
 
 extern int orch_check_and_handle_pcb_output(clickpcb_t *pcb, struct mbuf *send_m, int is_ipv6);
@@ -1248,6 +1249,11 @@
 	bzero(&ro, sizeof(struct route));
 	ro.ro_rt = rt;
 
+       if (geneve_aws_enable && m_tag_locate(m, MTAG_COOKIE_GENEVE, MTAG_GENEVE_AWS_OPTS, NULL)) {
+               error = geneve_transmit_for_aws(m);
+               clicktcp_leave_func(int, error);
+       }
+
 	if(llb_stat_enable) {
 		llb_stat_update(eroute_rule->gw, m->m_pkthdr.aext, m->m_pkthdr.len, m->m_pkthdr.rcvif);
 	}
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 39382)
+++ /branches/rel_apv_10_7/usr/src/sys/net/if_geneve.h	(working copy)
@@ -21,15 +21,17 @@
 #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 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_MIN                   0
 #define GENEVE_VNI_MAX                   (1 << 24)
 #define GENEVE_VNI_MASK                  (GENEVE_VNI_MAX - 1)
 #define GENEVE_HDR_VNI_SHIFT             (8)
+#define GENEVE_HDR_VER_SHIFT             (6)
+#define GENEVE_HDR_OPT_MAX_LEN           (252)
 
 #define GENEVE_MAX_TUNNEL                64
 #define GENEVE_VNI_MAX_TUNNEL            12      /* Max tunnels a vni can reside on */
@@ -47,6 +49,21 @@
 
 #define GENEVE_VER                       0
 
+/* AWS Geneve options */
+#define AWS_GENEVE_VNI                          0
+#define AWS_GENEVE_OPTION_LENGTH_SHIFT          3
+#define AWS_GENEVE_OPTION_CLASS_ID              0x0108
+#define AWS_GENEVE_OPTION_TYPE_VPCE_ID          0x01
+#define AWS_GENEVE_OPTION_TYPE_ATTACHMENT_ID    0x02
+#define AWS_GENEVE_OPTION_TYPE_FLOW_COOKIE      0x03
+#define AWS_GENEVE_OPTION_VPCE_ID_LEN           8
+#define AWS_GENEVE_OPTION_ATTACHMENT_ID_LEN     8
+#define AWS_GENEVE_OPTION_FLOW_COOKIE_LEN       4
+#define AWS_GENEVE_OPTION_LEN                   32
+
+#define MTAG_COOKIE_GENEVE     0X12341234
+#define MTAG_GENEVE_AWS_OPTS   1
+
 struct geneve_softc;
 LIST_HEAD(geneve_softc_head, geneve_softc);
 extern struct geneve_softc *geneve_softc_arr[MAX_GENEVE];
@@ -76,7 +93,7 @@
     uint8_t  r2:1;
     uint8_t  r3:1;
     uint8_t  length:5;
-    uint8_t  opt_data[];
+    /* uint8_t  opt_data[]; */
 } __packed;
 
 struct geneve_header {
@@ -118,6 +135,12 @@
     char                  cmd_ifname[IFNAMSIZ];
 };
 
+struct aws_geneve_tuple {
+    uint8_t               vpec_id[AWS_GENEVE_OPTION_VPCE_ID_LEN];
+    uint8_t               attachment_id[AWS_GENEVE_OPTION_ATTACHMENT_ID_LEN];
+    uint8_t               flow_cookie[AWS_GENEVE_OPTION_FLOW_COOKIE_LEN];
+};
+
 enum {
     GENEVE_DISABLE = 0,
     GENEVE_ENABLE,
@@ -140,8 +163,8 @@
 };
 
 enum geneve_mode {
-	GNV_P2MP = 0,
-	GNV_MCAST,
+    GNV_P2MP = 0,
+    GNV_MCAST,
 };
 
 #define GENEVE_DBG_ERR(fmt, ...) \
@@ -161,11 +184,19 @@
 
 #define GENEVE_DBG_INFO GENEVE_DBG_ENTER
 
+#define GENEVE_HEADER_GET_VER(m)     (((*(uint8_t *)m) & 0xC0) >> GENEVE_HDR_VER_SHIFT)
+#define GENEVE_HEADER_GET_OPT_LEN(m) (((*(uint8_t *)m) & 0x3F) * 4)
+#define GENEVE_HEADER_GET_VNI(m)     ntohl(m->vni) >> GENEVE_HDR_VNI_SHIFT
+#define GENEVE_OPT_HEADER_GET_LEN(m) ((*((uint8_t *)m + AWS_GENEVE_OPTION_LENGTH_SHIFT) & 0x1F) * 4)
+
 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);
+int geneve_transmit_for_aws(struct mbuf *);
+int geneve_options_parser_for_aws(struct mbuf *, int, uint8_t *, uint8_t *, uint8_t *);
+void geneve_learn_fwd_for_aws(uint8_t *, uint8_t *, uint8_t *, struct mbuf *, struct ip *, struct ip6_hdr *, 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);
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 39382)
+++ /branches/rel_apv_10_7/usr/src/sys/net/if_geneve.c	(working copy)
@@ -227,10 +227,21 @@
 int geneve_debug = GENEVE_DBG_OFF;
 SYSCTL_INT(_net_inet_clicktcp, OID_AUTO, geneve_debug, CTLFLAG_RW, &geneve_debug, 0, "geneve debug");
 
+int geneve_aws_enable = 0;
+SYSCTL_INT(_net_inet_clicktcp, OID_AUTO, geneve_aws_enable, CTLFLAG_RW, &geneve_aws_enable, 0, "aws geneve enable");
+
 static uint16_t geneve_pick_source_port(struct geneve_softc *, struct mbuf *);
+static void geneve_set_ip_header(struct ip *, uint16_t, uint8_t, struct in_addr *, struct in_addr*);
+static void geneve_set_ipv6_header(struct ip6_hdr *, uint16_t, uint8_t, struct in6_addr, struct in6_addr);
+static void geneve_set_udp_header(struct udphdr *, uint16_t, uint16_t, uint16_t);
+static void geneve_set_geneve_header(struct geneve_header *, uint8_t, uint8_t, uint8_t, uint8_t, uint16_t, uint32_t);
+static void geneve_set_geneve_option(struct geneve_opt *, uint16_t, uint8_t, uint8_t, uint8_t *);
 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 void geneve_encap_header_for_aws(struct geneve_softc *, struct aws_geneve_tuple *, struct mbuf *, int, uint16_t, uint16_t, int);
+static int geneve_encap4_send_for_aws(struct geneve_softc *, struct geneve_tunnel *, struct mbuf *, struct aws_geneve_tuple *);
+static int geneve_encap6_send_for_aws(struct geneve_softc *, struct geneve_tunnel *, struct mbuf *, struct aws_geneve_tuple *);
 
 static int  geneve_clone_create(struct if_clone *, int, caddr_t);
 static void geneve_clone_destroy(struct ifnet *);
@@ -299,9 +310,9 @@
 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 *);
+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);
@@ -533,20 +544,16 @@
     }
 
     /*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;
-                    }
+    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;
                 }
             }
         }
@@ -1566,6 +1573,115 @@
     return;
 }
 
+int 
+geneve_options_parser_for_aws(struct mbuf *m, int optlen, uint8_t *vpec_id, uint8_t *attachment_id, uint8_t *flow_cookie)
+{
+    struct geneve_opt *opt;
+    uint16_t class_id;
+    uint8_t type;
+    size_t offset = 0, len;
+
+    GENEVE_DBG_ENTER("m: %p, optlen: %d, vpec_id: %p, attachment_id: %p, flow_cookie: %p",
+                        m, optlen, vpec_id, attachment_id, flow_cookie);
+
+    while (offset + sizeof(struct geneve_opt) <= optlen) {
+        opt = mtodo(m, offset);
+        class_id = ntohs(opt->opt_class);
+        type = opt->type;
+        len = GENEVE_OPT_HEADER_GET_LEN(opt);
+
+        if (class_id != AWS_GENEVE_OPTION_CLASS_ID) {
+            GENEVE_DBG_ERR("Invalid class id of AWS geneve option");
+            return -1;
+        }
+
+        if (offset + len > optlen) {
+            GENEVE_DBG_ERR("Invalid length of geneve option");
+            return -1;
+        }
+
+        switch (type)
+        {
+            case AWS_GENEVE_OPTION_TYPE_VPCE_ID:
+                memcpy(vpec_id, ((uint8_t *)opt) + sizeof(struct geneve_opt), len);
+                break;
+            case AWS_GENEVE_OPTION_TYPE_ATTACHMENT_ID:
+                memcpy(attachment_id, ((uint8_t *)opt) + sizeof(struct geneve_opt), len);
+                break;
+            case AWS_GENEVE_OPTION_TYPE_FLOW_COOKIE:
+                memcpy(flow_cookie, ((uint8_t *)opt) + sizeof(struct geneve_opt), len);
+                break;
+            default:
+                GENEVE_DBG_ERR("Invalid type of AWS geneve option");
+                return -1;;
+        }
+
+        offset += len + sizeof(struct geneve_opt);
+    }
+
+    return 0;
+}
+
+void
+geneve_learn_fwd_for_aws(uint8_t *vpec_id, uint8_t *attach_id, uint8_t *flow_cookie, 
+                            struct mbuf *m, struct ip *ip, struct ip6_hdr *ip6, int isipv6)
+{
+    struct geneve_softc *sc;
+    struct ifnet *ifp;
+    struct m_tag *mtag;
+    struct aws_geneve_tuple *aws_tuple;
+    struct ether_header *eh;
+    uint8_t src_mac[ETHER_ADDR_LEN];
+
+    GENEVE_DBG_ENTER("vpec_id: %p, attach_id: %p, flow_cookie: %p, m: %p, ip: %p, ip6: %p, isipv6: %d",
+                        vpec_id, attach_id, flow_cookie, m, ip, ip6, isipv6);
+
+    sc = geneve_lookup_softc(AWS_GENEVE_VNI);
+    if (!sc) {
+        m_freem_atcp(m);
+        GENEVE_DBG_ERR("cannot find geneve softc");
+        return;
+    }
+
+    ifp = sc->geneve_ifp;
+
+    M_PREPEND(m, sizeof(struct ether_header), M_NOWAIT);
+    eh = mtod(m, struct ether_header *);
+
+    geneve_get_random_mac_addr(src_mac);
+    memcpy(eh->ether_shost, src_mac, ETHER_ADDR_LEN);
+    memcpy(eh->ether_dhost, sc->geneve_hwaddr, ETHER_ADDR_LEN);
+
+    if (isipv6) {
+        eh->ether_type = htons(ETHERTYPE_IPV6);
+    } else {
+        eh->ether_type = htons(ETHERTYPE_IP);
+    }
+
+    mtag = m_tag_alloc(MTAG_COOKIE_GENEVE, MTAG_GENEVE_AWS_OPTS, sizeof(struct aws_geneve_tuple), M_NOWAIT);
+    if (mtag == NULL) {
+        m_freem(m);
+        return;
+    }
+
+    aws_tuple = (struct aws_geneve_tuple *)(mtag + 1);
+
+    bzero(aws_tuple, sizeof(struct aws_geneve_tuple));
+    memcpy(aws_tuple->vpec_id, vpec_id, AWS_GENEVE_OPTION_VPCE_ID_LEN);
+    memcpy(aws_tuple->attachment_id, attach_id, AWS_GENEVE_OPTION_ATTACHMENT_ID_LEN);
+    memcpy(aws_tuple->flow_cookie, flow_cookie, AWS_GENEVE_OPTION_FLOW_COOKIE_LEN);
+
+    m_tag_prepend(m, mtag);
+
+    m_clrprotoflags(m);
+    m->m_pkthdr.rcvif = ifp;
+    M_SETFIB(m, ifp->if_fib);
+
+    (*ifp->if_input)(ifp, m);
+
+    return;
+}
+
 int
 geneve_tunnel_kern(void *pcb, char *tun_name, char *localip, char *remoteip)
 {
@@ -1595,7 +1711,7 @@
     }
 
     if(strstr(remoteip, ".") != NULL) {
-        if (inet_aton (remoteip, &remote) != 1) {
+        if (inet_aton(remoteip, &remote) != 1) {
             GENEVE_DBG_ERR("convert remoteip failed.");
             return -1;
         }
@@ -1762,7 +1878,7 @@
         GENEVE_DBG_ERR("This geneve interface doesn't exist.");
         return -1;
     }
-    
+
     geneve_clone_destroy(geneve_if);
 
     return 0;
@@ -1819,7 +1935,11 @@
     sc->geneve_vni = cmd->cmd_vni;
     if_dpdk_set_geneve_vni(sc->dpdk_host_ctx, sc->geneve_vni);
 
-    /*initialize geneve here.*/
+    if (sc->geneve_vni == AWS_GENEVE_VNI) {
+        geneve_aws_enable = 1;
+    }
+
+    /* initialize geneve here. */
     geneve_init((void*)sc);
 
     return 0;
@@ -2574,44 +2694,88 @@
 }
 
 static void
+geneve_set_ip_header(struct ip *ip, uint16_t len, uint8_t ttl, struct in_addr *srcaddr, struct in_addr *dstaddr)
+{
+    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 = ttl;
+    ip->ip_p = IPPROTO_UDP;
+    ip->ip_sum = 0;
+    ip->ip_src = *srcaddr;
+    ip->ip_dst = *dstaddr;
+}
+
+static void
+geneve_set_ipv6_header(struct ip6_hdr *ip6, uint16_t len, uint8_t ttl, struct in6_addr srcaddr, struct in6_addr dstaddr)
+{
+    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 = ttl;
+    ip6->ip6_src  = srcaddr;
+    ip6->ip6_dst  = dstaddr;
+}
+
+static void
+geneve_set_geneve_header(struct geneve_header *gh, uint8_t ver, uint8_t opt_len_bytes,
+                            uint8_t oam, uint8_t critical, uint16_t proto_type, uint32_t vni)
+{
+    ((uint8_t *)gh)[0] = (ver << 6) | ((opt_len_bytes / 4) & 0x3F); /* first 2 bits: ver, last 6 bits: opt_len */
+    gh->oam = oam ? 1 : 0;
+    gh->critical = critical ? 1 : 0;
+    gh->rsvd = 0;
+    gh->proto_type = htons(proto_type);
+    gh->vni = htonl((vni & 0xFFFFFF) << GENEVE_HDR_VNI_SHIFT);
+}
+
+static void
+geneve_set_udp_header(struct udphdr *udph, uint16_t srcport, uint16_t dstport, uint16_t len)
+{
+    udph->uh_sport = htons(srcport);
+    udph->uh_dport = htons(dstport);
+    udph->uh_ulen = htons(len);
+    udph->uh_sum = 0;
+}
+
+static void
+geneve_set_geneve_option(struct geneve_opt *opt, uint16_t class, uint8_t type, uint8_t len, uint8_t *data)
+{
+    opt->opt_class = htons(class);
+    opt->type = type;
+    ((uint8_t *)opt + AWS_GENEVE_OPTION_LENGTH_SHIFT)[0] = len / 4; /* first 3 bits: reserved, last 5 bits: len */
+    memcpy((uint8_t *)opt + sizeof(struct geneve_opt), data, len);
+}
+
+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);
+                        sc, sc->geneve_ifp->if_xname, geneve_tun->name, m, ipoff, srcport, 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;
+    geneve_set_udp_header(&hdr->uhdr, srcport, dstport, len);
 
-    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);
+    geneve_set_geneve_header(&hdr->ghdr, GENEVE_VER, 0, 0, 0, ETHERTYPE_TRANSETHER, sc->geneve_vni);
 
     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);
+            clickudp6_udp_cksum_sw(m, IPPROTO_UDP, sizeof(struct ip6_hdr), ntohs(ip6->ip6_plen), ip6, &hdr->uhdr, geneve_tun->ifp);
         } else {
-            clickudp6_cksum(m, IPPROTO_UDP, sizeof(struct ip6_hdr), ntohs(ip6->ip6_plen), ip6, udph, geneve_tun->ifp);
+            clickudp6_cksum(m, IPPROTO_UDP, sizeof(struct ip6_hdr), ntohs(ip6->ip6_plen), ip6, &hdr->uhdr, geneve_tun->ifp);
         }
     } else {
         if (m->m_pkthdr.len > geneve_tun->ifp->if_mtu) {
@@ -2628,7 +2792,6 @@
                     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;
@@ -2642,12 +2805,10 @@
         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);
+    srcport = ntohs(geneve_pick_source_port(sc, m));
     dstaddr = geneve_sa->in4.sin_addr;
+    dstport = (uint16_t)gtep.geneve_port;
 
     M_PREPEND(m, sizeof(struct ip) + sizeof(struct geneve_udphdr), M_NOWAIT);
     if (!m) {
@@ -2655,19 +2816,8 @@
         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_set_ip_header(ip, m->m_pkthdr.len, sc->geneve_ttl, &srcaddr, &dstaddr);
 
     geneve_encap_header(sc, geneve_tun, m, sizeof(struct ip), srcport, dstport, 0);
 
@@ -2706,7 +2856,6 @@
                     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;
@@ -2723,11 +2872,10 @@
         return -1;
     }
 
-    ifp = sc->geneve_ifp;
     srcaddr = &geneve_tun->src_addr.in6.sin6_addr;
-    srcport = geneve_pick_source_port(sc, m);
+    srcport = ntohs(geneve_pick_source_port(sc, m));
     dstaddr = &geneve_sa->in6.sin6_addr;
-    dstport = htons((uint16_t)gtep.geneve_port);
+    dstport = (uint16_t)gtep.geneve_port;
 
     M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct geneve_udphdr), M_NOWAIT);
     if (!m) {
@@ -2735,15 +2883,9 @@
     }
 
     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_set_ipv6_header(ip6, len, sc->geneve_ttl, *srcaddr, *dstaddr);
 
     geneve_encap_header(sc, geneve_tun, m, sizeof(struct ip6_hdr), srcport, dstport, 1);
 
@@ -2897,6 +3039,196 @@
 }
 
 static void
+geneve_encap_header_for_aws(struct geneve_softc *sc, struct aws_geneve_tuple *aws_tuple, struct mbuf *m, int ipoff,
+                            uint16_t srcport, uint16_t dstport, int is_ipv6)
+{
+    struct geneve_udphdr *hdr;
+    struct geneve_opt *opt;
+    struct ip6_hdr *ip6;
+    int len;
+    size_t optoff = 0;
+
+    GENEVE_DBG_ENTER("sc: %p, if_name: %s, aws_tuple: %p, m: %p, ipoff: %d, srcport: %d, dstport: %d, is_ipv6: %d",
+                        sc, sc->geneve_ifp->if_xname, aws_tuple, m, ipoff, srcport, dstport, is_ipv6);
+
+    len = m->m_pkthdr.len - ipoff;
+    MPASS(len >= sizeof(struct geneve_udphdr));
+    hdr = mtodo(m, ipoff);
+
+    geneve_set_udp_header(&hdr->uhdr, srcport, dstport, len);
+
+    geneve_set_geneve_header(&hdr->ghdr, GENEVE_VER, (aws_tuple ? AWS_GENEVE_OPTION_LEN : 0), 0, 0, (is_ipv6 ? ETHERTYPE_IPV6 : ETHERTYPE_IP), AWS_GENEVE_VNI);
+
+    /* vpec id */
+    optoff = ipoff + sizeof(struct geneve_udphdr);
+    opt = mtodo(m, optoff);
+    geneve_set_geneve_option(opt, AWS_GENEVE_OPTION_CLASS_ID, AWS_GENEVE_OPTION_TYPE_VPCE_ID, AWS_GENEVE_OPTION_VPCE_ID_LEN, aws_tuple->vpec_id);
+
+    /* attachment id */
+    optoff += sizeof(struct geneve_opt) + AWS_GENEVE_OPTION_VPCE_ID_LEN;
+    opt = mtodo(m, optoff);
+    geneve_set_geneve_option(opt, AWS_GENEVE_OPTION_CLASS_ID, AWS_GENEVE_OPTION_TYPE_ATTACHMENT_ID, AWS_GENEVE_OPTION_ATTACHMENT_ID_LEN, aws_tuple->attachment_id);
+
+    /* flow cookie */
+    optoff += sizeof(struct geneve_opt) + AWS_GENEVE_OPTION_ATTACHMENT_ID_LEN;
+    opt = mtodo(m, optoff);
+    geneve_set_geneve_option(opt, AWS_GENEVE_OPTION_CLASS_ID, AWS_GENEVE_OPTION_TYPE_FLOW_COOKIE, AWS_GENEVE_OPTION_FLOW_COOKIE_LEN, aws_tuple->flow_cookie);
+
+    if (is_ipv6) {
+        ip6 = mtod(m, struct ip6_hdr *);
+        if (m->m_pkthdr.len > sc->geneve_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, &hdr->uhdr, sc->geneve_ifp);
+        } else {
+            clickudp6_cksum(m, IPPROTO_UDP, sizeof(struct ip6_hdr), ntohs(ip6->ip6_plen), ip6, &hdr->uhdr, sc->geneve_ifp);
+        }
+    } else {
+        if (m->m_pkthdr.len > sc->geneve_ifp->if_mtu) {
+            /*hardware checksum may work abormal for UDP if IP fragment happened*/
+            clickudp_udp_cksum_sw(m, sc->geneve_ifp);
+        } else {
+            clickudp_cksum(m, sc->geneve_ifp);
+        }
+    }
+}
+
+static int
+geneve_encap4_send_for_aws(struct geneve_softc *sc, struct geneve_tunnel *tunnel, struct mbuf *m, struct aws_geneve_tuple *aws_tuple)
+{
+#ifdef INET
+    struct ip *ip;
+    struct in_addr srcaddr, dstaddr;
+    uint16_t srcport, dstport;
+
+    GENEVE_DBG_ENTER("sc: %p, aws_tuple: %p, m: %p", sc, aws_tuple, m);
+
+    srcaddr.s_addr = tunnel->src_addr.in4.sin_addr.s_addr;
+    srcport = ntohs(geneve_pick_source_port(sc, m));
+    dstaddr = tunnel->dst_addr.in4.sin_addr;
+    dstport = GENEVE_DEFAULT_PORT;
+
+    M_PREPEND(m, sizeof(struct ip) + sizeof(struct geneve_udphdr) + (aws_tuple ? AWS_GENEVE_OPTION_LEN : 0), M_NOWAIT);
+    if (!m) {
+        GENEVE_DBG_ERR("prepend mbuf failed.");
+        return ENOBUFS;
+    }
+
+    ip = mtod(m, struct ip *);
+    geneve_set_ip_header(ip, m->m_pkthdr.len, sc->geneve_ttl, &srcaddr, &dstaddr);
+
+    geneve_encap_header_for_aws(sc, aws_tuple, m, sizeof(struct ip), srcport, dstport, 0);
+
+    m->m_flags &= ~(M_MCAST | M_BCAST);
+
+    m_tag_delete(m, m_tag_locate(m, MTAG_COOKIE_GENEVE, MTAG_GENEVE_AWS_OPTS, NULL));
+
+    return ip_output(m, NULL, NULL, 0, NULL, NULL);
+
+#else
+    m_freem(m);
+    return ENOTSUP;
+#endif
+}
+
+static int
+geneve_encap6_send_for_aws(struct geneve_softc *sc, struct geneve_tunnel *tunnel, struct mbuf *m, struct aws_geneve_tuple *aws_tuple)
+{
+#ifdef INET6
+    struct ip6_hdr *ip6;
+    struct in6_addr srcaddr, dstaddr;
+    uint16_t len, srcport, dstport;
+
+    GENEVE_DBG_ENTER("sc: %p, aws_tuple: %p, m: %p", sc, aws_tuple, m);
+
+    srcaddr = tunnel->src_addr.in6.sin6_addr;
+    srcport = ntohs(geneve_pick_source_port(sc, m));
+    dstaddr = tunnel->dst_addr.in6.sin6_addr;
+    dstport = GENEVE_DEFAULT_PORT;
+
+    M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct geneve_udphdr), M_NOWAIT);
+    if (!m) {
+        return ENOBUFS;
+    }
+
+    ip6 = mtod(m, struct ip6_hdr *);
+    len = m->m_pkthdr.len - sizeof(struct ip6_hdr);
+    geneve_set_ipv6_header(ip6, len, sc->geneve_ttl, srcaddr, dstaddr);
+
+    geneve_encap_header_for_aws(sc, aws_tuple, m, sizeof(struct ip6_hdr), srcport, dstport, 1);
+
+    m->m_flags &= ~(M_MCAST | M_BCAST);
+
+    m_tag_delete(m, m_tag_locate(m, MTAG_COOKIE_GENEVE, MTAG_GENEVE_AWS_OPTS, NULL));
+
+    return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+
+#else
+    m_freem(m);
+    return ENOTSUP;
+#endif
+}
+
+int
+geneve_transmit_for_aws(struct mbuf *m)
+{
+    struct geneve_softc *sc;
+    struct ifnet *ifp;
+    struct m_tag *tag;
+    struct aws_geneve_tuple *aws_tuple;
+    struct geneve_tunnel *geneve_tun;
+    union geneve_sockaddr geneve_sa;
+    struct mbuf *n;
+    int i, error, isipv4;
+
+    GENEVE_DBG_ENTER("ifp: %p, if_name: %s, m: %p", ifp, ifp->if_xname, m);
+
+    ifp = get_geneve_ifp(AWS_GENEVE_VNI);
+    sc = ifp->if_softc;
+
+    if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+        m_freem(m);
+        return ENETDOWN;
+    }
+
+    GENEVE_ACQUIRE(sc);
+
+    tag = m_tag_locate(m, MTAG_COOKIE_GENEVE, MTAG_GENEVE_AWS_OPTS, NULL);
+    aws_tuple = (struct aws_geneve_tuple *)(tag + 1);
+
+    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);
+
+            /* For Unicast, lookup eroute and send out */
+            if (isipv4) {
+                error = geneve_encap4_send_for_aws(sc, geneve_tun, n, aws_tuple);
+            } else {
+                error = geneve_encap6_send_for_aws(sc, geneve_tun, n, aws_tuple);
+            }
+
+            if (error) {
+                GENEVE_DBG_ERR("error in geneve transmit [%d] for tunnel [%s].\n", error, geneve_tun->name);
+            }
+        }
+    }
+
+    geneve_release(sc);
+
+    return error;
+}
+
+static void
 geneve_qflush(struct ifnet *ifp __unused)
 {
 }
@@ -3163,7 +3495,7 @@
     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_flags = IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     ifp->if_init = geneve_init;
     ifp->if_ioctl = geneve_ioctl;
 
@@ -3193,7 +3525,7 @@
 
         return ENOSPC;
     }
-    
+
     LIST_INSERT_HEAD(&geneve_sc_list, sc, geneve_list_entry);
 
     return 0;
@@ -3231,6 +3563,10 @@
     free(sc, M_GENEVE);
 
     geneve_softc_arr[unit] = NULL;
+
+    if (sc->geneve_vni == AWS_GENEVE_VNI) {
+        geneve_aws_enable = 0;
+    }
 }
 
 static void
