[qca-nss-ecm]: Support for bond-L2DA mode

Added one callback to defuct all the connection
of a bond slave.

Change-Id: Ie04f3d4949951dbf0ca032b720f80e219c7fcb26
Signed-off-by: Suman Ghosh <sumang@codeaurora.org>
diff --git a/ecm_interface.c b/ecm_interface.c
index c482af6..e3d5247 100644
--- a/ecm_interface.c
+++ b/ecm_interface.c
@@ -5015,6 +5015,102 @@
 }
 
 /*
+ * ecm_interface_defunct_connections()
+ *	Cause defunct of all connections that are using the specified interface.
+ */
+static void ecm_interface_defunct_connections(struct ecm_db_iface_instance *ii)
+{
+#ifndef ECM_DB_XREF_ENABLE
+	ecm_db_connection_defunct_all();
+#else
+	struct ecm_db_connection_instance *ci_from;
+	struct ecm_db_connection_instance *ci_to;
+	struct ecm_db_connection_instance *ci_from_nat;
+	struct ecm_db_connection_instance *ci_to_nat;
+	struct ecm_db_connection_instance *ci_mcast __attribute__ ((unused));
+
+	DEBUG_TRACE("defunct connections using interface: %p\n", ii);
+
+	ci_from = ecm_db_iface_connections_from_get_and_ref_first(ii);
+	ci_to = ecm_db_iface_connections_to_get_and_ref_first(ii);
+	ci_from_nat = ecm_db_iface_connections_nat_from_get_and_ref_first(ii);
+	ci_to_nat = ecm_db_iface_connections_nat_to_get_and_ref_first(ii);
+
+	/*
+	 * Defunct all connections associated with this interface
+	 */
+	DEBUG_TRACE("%p: Defunct 'from' connections\n", ii);
+	while (ci_from) {
+		struct ecm_db_connection_instance *cin;
+		cin = ecm_db_connection_iface_from_get_and_ref_next(ci_from);
+
+		DEBUG_TRACE("%p: Defunct: %p", ii, ci_from);
+		ecm_db_connection_make_defunct(ci_from);
+		ecm_db_connection_deref(ci_from);
+		ci_from = cin;
+	}
+
+	DEBUG_TRACE("%p: Defunct 'to' connections\n", ii);
+	while (ci_to) {
+		struct ecm_db_connection_instance *cin;
+		cin = ecm_db_connection_iface_from_get_and_ref_next(ci_to);
+
+		DEBUG_TRACE("%p: Defunct: %p", ii, ci_to);
+		ecm_db_connection_make_defunct(ci_to);
+		ecm_db_connection_deref(ci_to);
+		ci_to = cin;
+	}
+
+	DEBUG_TRACE("%p: Defunct 'from_nat' connections\n", ii);
+	while (ci_from_nat) {
+		struct ecm_db_connection_instance *cin;
+		cin = ecm_db_connection_iface_from_get_and_ref_next(ci_from_nat);
+
+		DEBUG_TRACE("%p: Defunct: %p", ii, ci_from_nat);
+		ecm_db_connection_make_defunct(ci_from_nat);
+		ecm_db_connection_deref(ci_from_nat);
+		ci_from_nat = cin;
+	}
+
+	DEBUG_TRACE("%p: Defunct 'to_nat' connections\n", ii);
+	while (ci_to_nat) {
+		struct ecm_db_connection_instance *cin;
+		cin = ecm_db_connection_iface_from_get_and_ref_next(ci_to_nat);
+
+		DEBUG_TRACE("%p: Defunct: %p", ii, ci_to_nat);
+		ecm_db_connection_make_defunct(ci_to_nat);
+		ecm_db_connection_deref(ci_to_nat);
+		ci_to_nat = cin;
+	}
+#endif
+	DEBUG_TRACE("%p: Defunct COMPLETE\n", ii);
+}
+
+/*
+ * ecm_interface_dev_defunct_connections()
+ *	Cause defunct of all connections that are using the specified interface.
+ */
+void ecm_interface_dev_defunct_connections(struct net_device *dev)
+{
+	struct ecm_db_iface_instance *ii;
+
+	DEBUG_INFO("defunct connections for: %p (%s)\n", dev, dev->name);
+
+	/*
+	 * If the interface is known to us then we will get it returned by this
+	 * function and process it accordingly.
+	 */
+	ii = ecm_db_iface_find_and_ref_by_interface_identifier(dev->ifindex);
+	if (!ii) {
+		DEBUG_WARN("%p: No interface instance could be established for this dev\n", dev);
+		return;
+	}
+	ecm_interface_defunct_connections(ii);
+	DEBUG_TRACE("%p: defunct for %p: COMPLETE\n", dev, ii);
+	ecm_db_iface_deref(ii);
+}
+
+/*
  * ecm_interface_mtu_change()
  *	MTU of interface has changed
  */
diff --git a/ecm_interface.h b/ecm_interface.h
index 866dc68..be9b94a 100644
--- a/ecm_interface.h
+++ b/ecm_interface.h
@@ -104,3 +104,4 @@
 void ecm_interface_dev_regenerate_connections(struct net_device *dev);
 struct net_device *ecm_interface_dev_find_by_local_addr(ip_addr_t addr);
 bool ecm_interface_find_gateway(ip_addr_t addr, ip_addr_t gw_addr);
+void ecm_interface_dev_defunct_connections(struct net_device *dev);
diff --git a/frontends/nss/ecm_nss_bond_notifier.c b/frontends/nss/ecm_nss_bond_notifier.c
index fa61df5..b2eff6d 100644
--- a/frontends/nss/ecm_nss_bond_notifier.c
+++ b/frontends/nss/ecm_nss_bond_notifier.c
@@ -284,6 +284,74 @@
 }
 
 /*
+ * ecm_nss_bond_notifier_bond_delete_by_slave()
+ *	Callback when defunct a LAG slave
+ */
+static void ecm_nss_bond_notifier_bond_delete_by_slave(struct net_device *slave_dev)
+{
+	struct net_device *master;
+
+	/*
+	 * If operations have stopped then do not process event
+	 */
+	spin_lock_bh(&ecm_nss_bond_notifier_lock);
+	if (unlikely(ecm_nss_bond_notifier_stopped)) {
+		spin_unlock_bh(&ecm_nss_bond_notifier_lock);
+		DEBUG_WARN("Ignoring bond defunct event - stopped\n");
+		return;
+	}
+	spin_unlock_bh(&ecm_nss_bond_notifier_lock);
+
+	/*
+	 * A net device that is a LAG slave has to
+	 * defunct all the connection.
+	 * Due to the heiarchical nature of network topologies, this can
+	 * change the packet transmit path for any connection that is using
+	 * a device that it sitting "higher" in the heirarchy.
+	 */
+	master = ecm_interface_get_and_hold_dev_master(slave_dev);
+	if (!master) {
+		DEBUG_WARN("Failed to find 'master' for the slave:%s\n", slave_dev->name);
+		return;
+	}
+
+	ecm_interface_dev_defunct_connections(master);
+	dev_put(master);
+}
+
+/*
+ * ecm_nss_bond_notifier_bond_delete_by_mac()
+ *     This is a call back to delete all the rules with the mac address
+ */
+static void ecm_nss_bond_notifier_bond_delete_by_mac(uint8_t *mac)
+{
+	struct ecm_db_node_instance *ni;
+
+	if (unlikely(!mac)) {
+		DEBUG_WARN("mac address passed to ecm_nss_bond_notifier_bond_delete_by_mac is null \n");
+		return;
+	}
+
+	/*
+	 * find node instance corresponding to mac address
+	 */
+	ni = ecm_db_node_find_and_ref(mac);
+	if (unlikely(!ni)) {
+		DEBUG_WARN("node address is null\n");
+		return;
+	}
+
+	DEBUG_INFO("FDB updated for node %pM\n", mac);
+	ecm_db_traverse_node_from_connection_list_and_decelerate(ni);
+	ecm_db_traverse_node_to_connection_list_and_decelerate(ni);
+	ecm_db_traverse_node_from_nat_connection_list_and_decelerate(ni);
+	ecm_db_traverse_node_to_nat_connection_list_and_decelerate(ni);
+
+	ecm_db_node_deref(ni);
+	return;
+}
+
+/*
  * ecm_nss_bond_notifier_lag_event_cb()
  *	Handle LAG event from the NSS driver
  */
@@ -352,6 +420,8 @@
 	ecm_nss_bond_notifier_bond_cb.bond_cb_link_down = ecm_nss_bond_notifier_bond_link_down;
 	ecm_nss_bond_notifier_bond_cb.bond_cb_release = ecm_nss_bond_notifier_bond_release;
 	ecm_nss_bond_notifier_bond_cb.bond_cb_enslave = ecm_nss_bond_notifier_bond_enslave;
+	ecm_nss_bond_notifier_bond_cb.bond_cb_delete_by_slave = ecm_nss_bond_notifier_bond_delete_by_slave;
+	ecm_nss_bond_notifier_bond_cb.bond_cb_delete_by_mac = ecm_nss_bond_notifier_bond_delete_by_mac;
 	bond_register_cb(&ecm_nss_bond_notifier_bond_cb);
 
 	return 0;