[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;