[qca-nss-ecm] Add support for vxlan interface type.

Add support in ECM to identify VxLAN interface.

Change-Id: I83b0d381098dd799b9b57b00a531aecf68893cc7
Signed-off-by: Apoorv Gupta <apoogupt@codeaurora.org>
diff --git a/Makefile b/Makefile
index 8e78c5a..065875a 100644
--- a/Makefile
+++ b/Makefile
@@ -151,6 +151,12 @@
 ccflags-$(ECM_INTERFACE_RAWIP_ENABLE) += -DECM_INTERFACE_RAWIP_ENABLE
 
 # #############################################################################
+# Define ECM_INTERFACE_VXLAN_ENABLE=y in order
+# to enable support for VxLAN interface.
+# #############################################################################
+ccflags-$(ECM_INTERFACE_VXLAN_ENABLE) += -DECM_INTERFACE_VXLAN_ENABLE
+
+# #############################################################################
 # Define ECM_MULTICAST_ENABLE=y in order to enable support for ECM Multicast
 # #############################################################################
 ifeq ($(ECM_FRONT_END_NSS_ENABLE), y)
diff --git a/ecm_db/ecm_db_iface.c b/ecm_db/ecm_db_iface.c
index 7d89ea5..8f20dbd 100644
--- a/ecm_db/ecm_db_iface.c
+++ b/ecm_db/ecm_db_iface.c
@@ -113,7 +113,8 @@
 	"GRE_TUN",
 	"GRE_TAP",
 	"RAWIP",
-	"OVPN"
+	"OVPN",
+	"VxLAN"
 };
 
 /*
@@ -819,6 +820,37 @@
 }
 #endif
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+/*
+ * ecm_db_iface_vxlan_state_get()
+ *	Return interface type specific state
+ */
+static int ecm_db_iface_vxlan_state_get(struct ecm_db_iface_instance *ii, struct ecm_state_file_instance *sfi)
+{
+	int result;
+	uint32_t vni;
+
+	DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
+	spin_lock_bh(&ecm_db_lock);
+	vni = ii->type_info.vxlan.vni;
+	spin_unlock_bh(&ecm_db_lock);
+
+	if ((result = ecm_state_prefix_add(sfi, "vxlan"))) {
+		return result;
+	}
+
+	if ((result = ecm_db_iface_state_get_base(ii, sfi))) {
+		return result;
+	}
+
+	if ((result = ecm_state_write(sfi, "vni", "%d", vni))) {
+		return result;
+	}
+
+	return ecm_state_prefix_remove(sfi);
+}
+#endif
+
 /*
  * ecm_db_iface_state_get()
  *	Obtain state for the interface.
@@ -1301,6 +1333,19 @@
 }
 #endif
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+/*
+ * ecm_db_iface_generate_hash_index_vxlan()
+ *	Calculate the hash index based on VxLAN network identifier and interface type.
+ */
+static inline ecm_db_iface_hash_t ecm_db_iface_generate_hash_index_vxlan(uint32_t vni, uint32_t if_type)
+{
+	uint32_t hash_val;
+	hash_val = (uint32_t)jhash_2words(vni, if_type, ecm_db_jhash_rnd);
+	return (ecm_db_iface_hash_t)(hash_val & (ECM_DB_IFACE_HASH_SLOTS - 1));
+}
+#endif
+
 /*
  * ecm_db_iface_ethernet_address_get()
  *	Obtain the ethernet address for an ethernet interface
@@ -1555,6 +1600,47 @@
 EXPORT_SYMBOL(ecm_db_iface_find_and_ref_vlan);
 #endif
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+/*
+ * ecm_db_iface_find_and_ref_vxlan()
+ *	Lookup and return a iface reference if any
+ */
+struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_vxlan(uint32_t vni, uint32_t type)
+{
+	ecm_db_iface_hash_t hash_index;
+	struct ecm_db_iface_instance *ii;
+
+	DEBUG_TRACE("Lookup vxlan iface with vxlan id: %d & if_type: %d\n", vni, type);
+
+	/*
+	 * Compute the hash chain index and prepare to walk the chain
+	 */
+	hash_index = ecm_db_iface_generate_hash_index_vxlan(vni, type);
+
+	/*
+	 * Iterate the chain looking for a host with matching details
+	 */
+	spin_lock_bh(&ecm_db_lock);
+	ii = ecm_db_iface_table[hash_index];
+	while (ii) {
+		if ((ii->type != ECM_DB_IFACE_TYPE_VXLAN)
+			|| (ii->type_info.vxlan.vni != vni)
+			|| (ii->type_info.vxlan.if_type != type)) {
+			ii = ii->hash_next;
+			continue;
+		}
+
+		_ecm_db_iface_ref(ii);
+		spin_unlock_bh(&ecm_db_lock);
+		DEBUG_TRACE("iface found %p\n", ii);
+		return ii;
+	}
+	spin_unlock_bh(&ecm_db_lock);
+	DEBUG_TRACE("Iface not found\n");
+	return NULL;
+}
+#endif
+
 /*
  * ecm_db_iface_find_and_ref_bridge()
  *	Lookup and return a iface reference if any
@@ -3210,6 +3296,58 @@
 EXPORT_SYMBOL(ecm_db_iface_add_ovpn);
 #endif
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+/*
+ * ecm_db_iface_add_vxlan()
+ *	Add a iface instance into the database
+ */
+void ecm_db_iface_add_vxlan(struct ecm_db_iface_instance *ii, uint32_t vni, uint32_t if_type,
+					char *name, int32_t mtu, int32_t interface_identifier,
+					int32_t ae_interface_identifier,
+					ecm_db_iface_final_callback_t final, void *arg)
+{
+	ecm_db_iface_hash_t hash_index;
+	struct ecm_db_interface_info_vxlan *type_info;
+
+	spin_lock_bh(&ecm_db_lock);
+	DEBUG_CHECK_MAGIC(ii, ECM_DB_IFACE_INSTANCE_MAGIC, "%p: magic failed\n", ii);
+#ifdef ECM_DB_XREF_ENABLE
+	DEBUG_ASSERT((ii->nodes == NULL) && (ii->node_count == 0), "%p: nodes not null\n", ii);
+#endif
+	DEBUG_ASSERT(!(ii->flags & ECM_DB_IFACE_FLAGS_INSERTED), "%p: inserted\n", ii);
+	DEBUG_ASSERT(name, "%p: no name given\n", ii);
+	spin_unlock_bh(&ecm_db_lock);
+
+	/*
+	 * Record general info
+	 */
+	ii->type = ECM_DB_IFACE_TYPE_VXLAN;
+#ifdef ECM_STATE_OUTPUT_ENABLE
+	ii->state_get = ecm_db_iface_vxlan_state_get;
+#endif
+	ii->arg = arg;
+	ii->final = final;
+	strlcpy(ii->name, name, IFNAMSIZ);
+	ii->mtu = mtu;
+	ii->interface_identifier = interface_identifier;
+	ii->ae_interface_identifier = ae_interface_identifier;
+
+	/*
+	 * Type specific info
+	 */
+	type_info = &ii->type_info.vxlan;
+	type_info->vni = vni;
+	type_info->if_type = if_type;
+
+	/*
+	 * Compute hash chain for insertion
+	 */
+	hash_index = ecm_db_iface_generate_hash_index_vxlan(vni, if_type);
+
+	ecm_db_iface_add_to_db(ii, hash_index);
+}
+#endif
+
 /*
  * ecm_db_iface_alloc()
  *	Allocate a iface instance
diff --git a/ecm_db/ecm_db_iface.h b/ecm_db/ecm_db_iface.h
index a428f75..0722c19 100644
--- a/ecm_db/ecm_db_iface.h
+++ b/ecm_db/ecm_db_iface.h
@@ -132,6 +132,9 @@
 #ifdef ECM_INTERFACE_OVPN_ENABLE
 		struct ecm_db_interface_info_ovpn ovpn;			/* type == ECM_DB_IFACE_TYPE_OVPN (OpenVPN tunnel - data channel offload interface) */
 #endif
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+		struct ecm_db_interface_info_vxlan vxlan;			/* type == ECM_DB_IFACE_TYPE_VXLAN */
+#endif
 	} type_info;
 
 #ifdef ECM_STATE_OUTPUT_ENABLE
@@ -295,6 +298,15 @@
 				ecm_db_iface_final_callback_t final, void *arg);
 #endif
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+struct ecm_db_iface_instance *ecm_db_iface_find_and_ref_vxlan(uint32_t vni, uint32_t if_type);
+void ecm_db_iface_add_vxlan(struct ecm_db_iface_instance *ii,
+			   uint32_t vni, uint32_t if_type, char *name,
+			   int32_t mtu, int32_t interface_identifier,
+			   int32_t ae_interface_identifier,
+			   ecm_db_iface_final_callback_t final, void *arg);
+#endif
+
 struct ecm_db_iface_instance *ecm_db_interfaces_get_and_ref_first(void);
 struct ecm_db_iface_instance *ecm_db_interface_get_and_ref_next(struct ecm_db_iface_instance *ii);
 
diff --git a/ecm_db/ecm_db_types.h b/ecm_db/ecm_db_types.h
index 3183660..feb2f0b 100644
--- a/ecm_db/ecm_db_types.h
+++ b/ecm_db/ecm_db_types.h
@@ -268,6 +268,7 @@
 	ECM_DB_IFACE_TYPE_GRE_TAP,			/* Interface is a GRE TAP tunnel interface */
 	ECM_DB_IFACE_TYPE_RAWIP,			/* Interface is a RAWIP interface */
 	ECM_DB_IFACE_TYPE_OVPN,				/* Interface is a OVPN interface */
+	ECM_DB_IFACE_TYPE_VXLAN,			/* Interface is a VxLAN interface */
 	ECM_DB_IFACE_TYPE_COUNT,			/* Number of interface types */
 };
 typedef enum ecm_db_iface_types ecm_db_iface_type_t;
@@ -279,6 +280,13 @@
 	uint8_t address[ETH_ALEN];			/* MAC Address of this Interface */
 };
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+struct ecm_db_interface_info_vxlan {			/* type == ECM_DB_IFACE_TYPE_VXLAN */
+	uint32_t vni;					/* VxLAN network identifier */
+	uint32_t if_type;				/* VxLAN interface type */
+};
+#endif
+
 #ifdef ECM_INTERFACE_VLAN_ENABLE
 struct ecm_db_interface_info_vlan {			/* type == ECM_DB_IFACE_TYPE_VLAN */
 	uint8_t address[ETH_ALEN];			/* MAC Address of this Interface */
diff --git a/ecm_interface.c b/ecm_interface.c
index 3f8554b..e5108a5 100644
--- a/ecm_interface.c
+++ b/ecm_interface.c
@@ -88,6 +88,9 @@
 #ifdef ECM_INTERFACE_MAP_T_ENABLE
 #include <nat46-core.h>
 #endif
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+#include <net/vxlan.h>
+#endif
 
 /*
  * Debug output levels
@@ -973,6 +976,44 @@
 EXPORT_SYMBOL(ecm_interface_multicast_check_for_src_ifindex);
 #endif
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+/*
+ * ecm_interface_vxlan_type_get()
+ *	Function to get VxLAN interface type i.e. inner/outer.
+ *	Returns 0 for outer and 1 for inner.
+ */
+uint32_t ecm_interface_vxlan_type_get(struct sk_buff *skb)
+{
+	ip_addr_t saddr;
+	struct net_device *local_dev;
+
+	if (!skb) {
+		return -1;
+	}
+
+	switch (ntohs(skb->protocol)) {
+	case ETH_P_IP:
+		ECM_NIN4_ADDR_TO_IP_ADDR(saddr, ip_hdr(skb)->saddr);
+		break;
+	case ETH_P_IPV6:
+		ECM_NIN6_ADDR_TO_IP_ADDR(saddr, ipv6_hdr(skb)->saddr);
+		break;
+	default:
+		DEBUG_WARN("%p: Unknown skb protocol.\n", skb);
+		return -1;
+	}
+
+	local_dev = ecm_interface_dev_find_by_local_addr(saddr);
+	if (local_dev) {
+		dev_put(local_dev);
+		DEBUG_TRACE("%p: VxLAN outer interface type.\n", skb);
+		return 0;
+	}
+	DEBUG_TRACE("%p: VxLAN inner interface type.\n", skb);
+	return 1;
+}
+#endif
+
 /*
  * ecm_interface_addr_find_route_by_addr_ipv4()
  *	Return the route for the given IP address.  Returns NULL on failure.
@@ -2181,6 +2222,64 @@
 }
 #endif
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+/*
+ * ecm_interface_vxlan_interface_establish()
+ *	Returns a reference to a iface of the VxLAN type, possibly creating one if necessary.
+ * Returns NULL on failure or a reference to interface.
+ */
+static struct ecm_db_iface_instance *ecm_interface_vxlan_interface_establish(struct ecm_db_interface_info_vxlan *type_info,
+							char *dev_name, int32_t dev_interface_num, int32_t ae_interface_num, int32_t mtu)
+{
+	struct ecm_db_iface_instance *nii;
+	struct ecm_db_iface_instance *ii;
+
+	DEBUG_INFO("Establish VxLAN iface: %s with vxlan id: %u, MTU: %d, if num: %d, if_type: %d, accel engine if id: %d\n",
+			dev_name, type_info->vni, mtu, dev_interface_num, type_info->if_type, ae_interface_num);
+
+	/*
+	 * Locate the iface
+	 */
+	ii = ecm_db_iface_find_and_ref_vxlan(type_info->vni, type_info->if_type);
+	if (ii) {
+		DEBUG_TRACE("%p: vxlan iface established\n", ii);
+		/*
+		 * Update the accel engine interface identifier, just in case it was changed.
+		 */
+		ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
+		return ii;
+	}
+
+	/*
+	 * No iface - create one
+	 */
+	nii = ecm_db_iface_alloc();
+	if (!nii) {
+		DEBUG_WARN("Failed to establish iface\n");
+		return NULL;
+	}
+
+	/*
+	 * Add iface into the database, atomically to avoid races creating the same thing
+	 */
+	spin_lock_bh(&ecm_interface_lock);
+	ii = ecm_db_iface_find_and_ref_vxlan(type_info->vni, type_info->if_type);
+	if (ii) {
+		spin_unlock_bh(&ecm_interface_lock);
+		ecm_db_iface_deref(nii);
+		ecm_db_iface_update_ae_interface_identifier(ii, ae_interface_num);
+		DEBUG_TRACE("%p: vxlan iface established\n", ii);
+		return ii;
+	}
+	ecm_db_iface_add_vxlan(nii, type_info->vni, type_info->if_type, dev_name, mtu,
+			dev_interface_num, ae_interface_num, NULL, nii);
+	spin_unlock_bh(&ecm_interface_lock);
+
+	DEBUG_TRACE("%p: vxlan iface established\n", nii);
+	return nii;
+}
+#endif
+
 /*
  * ecm_interface_tunnel_mtu_update()
  *	Update mtu if the flow is a tunneled packet.
@@ -2199,6 +2298,7 @@
 
 	switch (type) {
 	case ECM_DB_IFACE_TYPE_IPSEC_TUNNEL:
+	case ECM_DB_IFACE_TYPE_VXLAN:
 		if (!src_dev && !dest_dev) {
 			return false;
 		}
@@ -2303,6 +2403,9 @@
 #ifdef ECM_INTERFACE_OVPN_ENABLE
 		struct ecm_db_interface_info_ovpn ovpn;			/* type == ECM_DB_IFACE_TYPE_OVPN */
 #endif
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+		struct ecm_db_interface_info_vxlan vxlan;		/* type == ECM_DB_IFACE_TYPE_VXLAN */
+#endif
 	} type_info;
 
 #ifdef ECM_INTERFACE_GRE_TUN_ENABLE
@@ -2386,6 +2489,54 @@
 		}
 #endif
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+		/*
+		 * VxLAN?
+		 */
+		if (is_vxlan_dev(dev)) {
+			struct vxlan_dev *vxlan_tun;
+			ip_addr_t vxlan_saddr, vxlan_daddr;
+
+			/*
+			 * VxLAN
+			 */
+			vxlan_tun = netdev_priv(dev);
+
+			DEBUG_TRACE("%p: Net device: %p is VxLAN, mac: %pM, vni: %d\n",
+					feci, dev, dev->dev_addr, vxlan_tun->cfg.vni);
+
+			interface_type = ecm_interface_vxlan_type_get(skb);
+			ae_interface_num = feci->ae_interface_number_by_dev_type_get(dev, interface_type);
+			DEBUG_TRACE("%p: VxLAN netdevice interface ae_interface_num: %d, interface_type: %d\n",
+					feci, ae_interface_num, interface_type);
+
+			type_info.vxlan.vni = vxlan_tun->cfg.vni;
+			type_info.vxlan.if_type = interface_type;
+
+			/*
+			 * Copy IP addresses from skb
+			 */
+			if (ip_hdr(skb)->version == IPVERSION) {
+				ECM_NIN4_ADDR_TO_IP_ADDR(vxlan_saddr, ip_hdr(skb)->saddr);
+				ECM_NIN4_ADDR_TO_IP_ADDR(vxlan_daddr, ip_hdr(skb)->daddr);
+			} else {
+				ECM_NIN6_ADDR_TO_IP_ADDR(vxlan_saddr, ipv6_hdr(skb)->saddr);
+				ECM_NIN6_ADDR_TO_IP_ADDR(vxlan_daddr, ipv6_hdr(skb)->daddr);
+			}
+
+			if (ecm_interface_tunnel_mtu_update(vxlan_saddr, vxlan_daddr,
+						ECM_DB_IFACE_TYPE_VXLAN, &dev_mtu)) {
+				DEBUG_TRACE("%p: VxLAN netdevice mtu updated: %d\n", feci, dev_mtu);
+			}
+
+			/*
+			 * Establish this type of interface
+			 */
+			ii = ecm_interface_vxlan_interface_establish(&type_info.vxlan, dev_name, dev_interface_num, ae_interface_num, dev_mtu);
+			goto identifier_update;
+		}
+#endif
+
 		/*
 		 * BRIDGE?
 		 */
@@ -4029,6 +4180,23 @@
 	}
 #endif
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+	/*
+	 * if the address is a local address and indev=VxLAN.
+	 */
+	if (from_local_addr &&
+	    given_dest_dev &&
+	    (given_dest_dev->type == ARPHRD_ETHER) &&
+	    (is_vxlan_dev(given_dest_dev))) {
+		dev_put(dest_dev);
+		dest_dev = given_dest_dev;
+		if (dest_dev) {
+			dev_hold(dest_dev);
+			DEBUG_TRACE("%p: VxLAN tunnel packet with dest_addr: " ECM_IP_ADDR_OCTAL_FMT " uses dev: %p(%s)\n", feci, ECM_IP_ADDR_TO_OCTAL(dest_addr), dest_dev, dest_dev->name);
+		}
+	}
+#endif
+
 	if (!dest_dev) {
 		DEBUG_WARN("%p: dest_addr: " ECM_IP_ADDR_OCTAL_FMT " - cannot locate device\n", feci, ECM_IP_ADDR_TO_OCTAL(dest_addr));
 		return ECM_DB_IFACE_HEIRARCHY_MAX;
diff --git a/frontends/nss/ecm_nss_common.h b/frontends/nss/ecm_nss_common.h
index 630826e..e39f8d1 100644
--- a/frontends/nss/ecm_nss_common.h
+++ b/frontends/nss/ecm_nss_common.h
@@ -26,6 +26,10 @@
 #endif
 #endif
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+#include <net/vxlan.h>
+#endif
+
 /*
  * Some constants used with constructing NSS acceleration rules.
  * GGG TODO These should be provided by the NSS driver itself!
@@ -88,6 +92,18 @@
 		return NSS_IPSEC_CMN_INTERFACE;
 	}
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+	/*
+	 * Find VxLAN dev type based on type, 0 for outer & 1 for inner.
+	 */
+	if (is_vxlan_dev(dev)) {
+		if (!type) {
+			return NSS_VXLAN_INTERFACE;
+		}
+		type = NSS_DYNAMIC_INTERFACE_TYPE_VXLAN_INNER;
+	}
+#endif
+
 	return nss_cmn_get_interface_number_by_dev_and_type(dev, type);
 }
 
diff --git a/frontends/nss/ecm_nss_ipv4.c b/frontends/nss/ecm_nss_ipv4.c
index 439678b..8805211 100644
--- a/frontends/nss/ecm_nss_ipv4.c
+++ b/frontends/nss/ecm_nss_ipv4.c
@@ -44,6 +44,9 @@
 #include <linux/netfilter_bridge.h>
 #include <linux/if_bridge.h>
 #include <net/arp.h>
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+#include <net/vxlan.h>
+#endif
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_acct.h>
 #include <net/netfilter/nf_conntrack_helper.h>
@@ -533,6 +536,28 @@
 			DEBUG_TRACE("OVPN interface unsupported\n");
 			return NULL;
 #endif
+		case ECM_DB_IFACE_TYPE_VXLAN:
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+			local_dev = ecm_interface_dev_find_by_local_addr(addr);
+			if (!local_dev) {
+				DEBUG_WARN("%p: Failed to find local netdevice of VxLAN tunnel for " ECM_IP_ADDR_DOT_FMT "\n",
+						feci, ECM_IP_ADDR_TO_DOT(addr));
+				return NULL;
+			}
+
+			if (!ecm_interface_mac_addr_get_no_route(local_dev, addr, node_addr)) {
+				DEBUG_WARN("%p: Couldn't find mac address for local dev\n", feci);
+				dev_put(local_dev);
+				return NULL;
+			}
+			DEBUG_TRACE("%p: Found the mac address for local dev\n", feci);
+			dev_put(local_dev);
+			done = true;
+			break;
+#else
+			DEBUG_TRACE("%p: VXLAN interface unsupported\n", feci);
+			return NULL;
+#endif
 		default:
 			/*
 			 * Don't know how to handle these.
@@ -1084,6 +1109,31 @@
 		sender = ECM_TRACKER_SENDER_TYPE_SRC;
 	} else {
 		if (unlikely(ct == nf_ct_untracked_get())) {
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+			/*
+			 * If the conntrack connection is set as untracked,
+			 * ECM will accept and process only VxLAN outer flows,
+			 * otherwise such flows will not be processed by ECM.
+			 *
+			 * E.g. In the following network arramgement,
+			 * Eth1 ---> Bridge ---> VxLAN0(Bridge Port) ---> Eth0(WAN)
+			 * The packets from VxLAN0 to Eth0 will be routed.
+			 *
+			 * is_vxlan_dev API is used to identify the VxLAN device &
+			 * is_routed flag is used to identify the outer flow.
+			 */
+			if (is_routed && is_vxlan_dev(in_dev)) {
+				DEBUG_TRACE("%p: Untracked CT for VxLAN\n", skb);
+				ECM_IP_ADDR_TO_NIN4_ADDR(orig_tuple.src.u3.ip, ip_hdr.src_addr);
+				ECM_IP_ADDR_TO_NIN4_ADDR(orig_tuple.dst.u3.ip, ip_hdr.dest_addr);
+				orig_tuple.dst.protonum = ip_hdr.protocol;
+				reply_tuple.src.u3.ip = orig_tuple.dst.u3.ip;
+				reply_tuple.dst.u3.ip = orig_tuple.src.u3.ip;
+				sender = ECM_TRACKER_SENDER_TYPE_SRC;
+				ct = NULL;
+				goto vxlan_done;
+			}
+#endif
 			DEBUG_TRACE("%p: ct: untracked\n", skb);
 			return NF_ACCEPT;
 		}
@@ -1121,6 +1171,10 @@
 			orig_tuple.dst.protonum = ip_hdr.protocol;
 			DEBUG_TRACE("%p: related ct, actual protocol: %u\n", skb, orig_tuple.dst.protonum);
 		}
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+vxlan_done:
+		;
+#endif
 	}
 
 	/*
diff --git a/frontends/nss/ecm_nss_ipv6.c b/frontends/nss/ecm_nss_ipv6.c
index afb9b1c..338fcdb 100644
--- a/frontends/nss/ecm_nss_ipv6.c
+++ b/frontends/nss/ecm_nss_ipv6.c
@@ -47,6 +47,9 @@
 #include <linux/netfilter_bridge.h>
 #include <linux/if_bridge.h>
 #include <net/arp.h>
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+#include <net/vxlan.h>
+#endif
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_acct.h>
 #include <net/netfilter/nf_conntrack_helper.h>
@@ -566,6 +569,28 @@
 			DEBUG_TRACE("OVPN interface unsupported\n");
 			return NULL;
 #endif
+		case ECM_DB_IFACE_TYPE_VXLAN:
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+			local_dev = ecm_interface_dev_find_by_local_addr(addr);
+			if (!local_dev) {
+				DEBUG_WARN("%p: Failed to find local netdevice of VxLAN tunnel for " ECM_IP_ADDR_OCTAL_FMT "\n",
+						feci, ECM_IP_ADDR_TO_OCTAL(addr));
+				return NULL;
+			}
+
+			if (!ecm_interface_mac_addr_get_no_route(local_dev, addr, node_addr)) {
+				DEBUG_WARN("%p: Couldn't find mac address for local dev\n", feci);
+				dev_put(local_dev);
+				return NULL;
+			}
+			DEBUG_TRACE("%p: Found the mac address for local dev\n", feci);
+			dev_put(local_dev);
+			done = true;
+			break;
+#else
+			DEBUG_TRACE("VXLAN interface unsupported\n");
+			return NULL;
+#endif
 		default:
 			/*
 			 * Don't know how to handle these.
@@ -1066,6 +1091,31 @@
 		sender = ECM_TRACKER_SENDER_TYPE_SRC;
 	} else {
 		if (unlikely(ct == nf_ct_untracked_get())) {
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+			/*
+			 * If the conntrack connection is set as untracked,
+			 * ECM will accept and process only VxLAN outer flows,
+			 * otherwise such flows will not be processed by ECM.
+			 *
+			 * E.g. In the following network arramgement,
+			 * Eth1 ---> Bridge ---> VxLAN0(Bridge Port) ---> Eth0(WAN)
+			 * The packets from VxLAN0 to Eth0 will be routed.
+			 *
+			 * is_vxlan_dev API is used to identify the VxLAN device &
+			 * is_routed flag is used to identify the outer flow.
+			 */
+			if (is_routed && is_vxlan_dev(in_dev)) {
+				DEBUG_TRACE("%p: Untracked CT for VxLAN\n", skb);
+				ECM_IP_ADDR_TO_NIN6_ADDR(orig_tuple.src.u3.in6, ip_hdr.src_addr);
+				ECM_IP_ADDR_TO_NIN6_ADDR(orig_tuple.dst.u3.in6, ip_hdr.dest_addr);
+				orig_tuple.dst.protonum = ip_hdr.protocol;
+				ECM_IP_ADDR_TO_NIN6_ADDR(reply_tuple.src.u3.in6, ip_hdr.dest_addr);
+				ECM_IP_ADDR_TO_NIN6_ADDR(reply_tuple.dst.u3.in6, ip_hdr.src_addr);
+				sender = ECM_TRACKER_SENDER_TYPE_SRC;
+				ct = NULL;
+				goto vxlan_done;
+			}
+#endif
 			DEBUG_TRACE("%p: ct: untracked\n", skb);
 			return NF_ACCEPT;
 		}
@@ -1103,6 +1153,10 @@
 			orig_tuple.dst.protonum = ip_hdr.protocol;
 			DEBUG_TRACE("%p: related ct, actual protocol: %u\n", skb, orig_tuple.dst.protonum);
 		}
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+vxlan_done:
+		;
+#endif
 	}
 
 	/*
diff --git a/frontends/nss/ecm_nss_ported_ipv4.c b/frontends/nss/ecm_nss_ported_ipv4.c
index e56ca98..edba8d2 100644
--- a/frontends/nss/ecm_nss_ported_ipv4.c
+++ b/frontends/nss/ecm_nss_ported_ipv4.c
@@ -51,6 +51,9 @@
 #include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+#include <net/vxlan.h>
+#endif
 #include <linux/netfilter/nf_conntrack_tftp.h>
 #ifdef ECM_INTERFACE_VLAN_ENABLE
 #include <linux/../../net/8021q/vlan.h>
@@ -685,6 +688,31 @@
 			DEBUG_TRACE("%p: OVPN - unsupported\n", npci);
 #endif
 			break;
+		case ECM_DB_IFACE_TYPE_VXLAN:
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+			DEBUG_TRACE("%p: From VXLAN interface\n", npci);
+			if (interface_type_counts[ii_type] != 0) {
+				/*
+				 * Can support only one VxLAN interface.
+				 */
+				DEBUG_WARN("%p: VxLAN - ignore additional\n", npci);
+				rule_invalid = true;
+				break;
+			}
+
+			/*
+			 * For VxLAN device, a 5-tuple connection rule is added with
+			 * the same src and dest ports in both the directions.
+			 */
+			if (ecm_db_connection_is_routed_get(feci->ci)) {
+				nircm->conn_rule.return_mtu = nircm->conn_rule.flow_mtu;
+				nircm->rule_flags |= NSS_IPV4_RULE_CREATE_FLAG_NO_SRC_IDENT;
+			}
+#else
+			rule_invalid = true;
+			DEBUG_TRACE("%p: VXLAN - unsupported\n", npci);
+#endif
+			break;
 		default:
 			DEBUG_TRACE("%p: Ignoring: %d (%s)\n", npci, ii_type, ii_name);
 		}
@@ -1790,7 +1818,7 @@
 		return result;
 	}
 
- 	return ecm_state_prefix_remove(sfi);
+	return ecm_state_prefix_remove(sfi);
 }
 #endif
 
@@ -2036,6 +2064,12 @@
 			}
 		}
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+		if ((is_vxlan_dev(in_dev) || is_vxlan_dev(out_dev)) && is_routed) {
+			DEBUG_TRACE("VxLAN outer connection, make src and dest idents same\n");
+			src_port = src_port_nat = dest_port;
+		}
+#endif
 		if (ct && nfct_help(ct) && (dest_port == TFTP_PORT)) {
 			DEBUG_TRACE("%p: Connection has helper but protocol is TFTP, it can be accelerated\n", ct);
 			can_accel = true;
diff --git a/frontends/nss/ecm_nss_ported_ipv6.c b/frontends/nss/ecm_nss_ported_ipv6.c
index 514db77..aaab1bf 100644
--- a/frontends/nss/ecm_nss_ported_ipv6.c
+++ b/frontends/nss/ecm_nss_ported_ipv6.c
@@ -52,6 +52,9 @@
 #include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+#include <net/vxlan.h>
+#endif
 #include <linux/netfilter/nf_conntrack_tftp.h>
 #ifdef ECM_INTERFACE_VLAN_ENABLE
 #include <linux/../../net/8021q/vlan.h>
@@ -655,6 +658,30 @@
 			rule_invalid = true;
 			DEBUG_TRACE("%p: OVPN - unsupported\n", npci);
 #endif
+		case ECM_DB_IFACE_TYPE_VXLAN:
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+			DEBUG_TRACE("%p: From VXLAN interface\n", npci);
+			if (interface_type_counts[ii_type] != 0) {
+				/*
+				 * Can support only one VxLAN interface.
+				 */
+				DEBUG_WARN("%p: VxLAN - ignore additional\n", npci);
+				rule_invalid = true;
+				break;
+			}
+
+			/*
+			 * For VxLAN device, a 5-tuple connection rule is added with
+			 * the same src and dest ports in both the directions.
+			 */
+			if (ecm_db_connection_is_routed_get(feci->ci)) {
+				nircm->conn_rule.return_mtu = nircm->conn_rule.flow_mtu;
+				nircm->rule_flags |= NSS_IPV6_RULE_CREATE_FLAG_NO_SRC_IDENT;
+			}
+#else
+			rule_invalid = true;
+			DEBUG_TRACE("%p: VXLAN - unsupported\n", npci);
+#endif
 			break;
 		default:
 			DEBUG_TRACE("%p: Ignoring: %d (%s)\n", npci, ii_type, ii_name);
@@ -1921,6 +1948,12 @@
 			}
 		}
 
+#ifdef ECM_INTERFACE_VXLAN_ENABLE
+		if ((is_vxlan_dev(in_dev) || is_vxlan_dev(out_dev)) && is_routed) {
+			DEBUG_TRACE("VxLAN outer connection, make src and dest idents same.\n");
+			src_port = dest_port;
+		}
+#endif
 		if (ct && nfct_help(ct) && (dest_port == TFTP_PORT)) {
 			DEBUG_TRACE("%p: Connection has helper but protocol is TFTP, it can be accelerated\n", ct);
 			can_accel = true;