mirror of
				https://github.com/Ysurac/openmptcprouter.git
				synced 2025-03-09 15:40:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			685 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			685 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
--- a/drivers/net/bonding/bond_3ad.c
 | 
						|
+++ b/drivers/net/bonding/bond_3ad.c
 | 
						|
@@ -116,6 +116,40 @@ static void ad_marker_response_received(
 | 
						|
 					struct port *port);
 | 
						|
 static void ad_update_actor_keys(struct port *port, bool reset);
 | 
						|
 
 | 
						|
+/* QCA NSS ECM bonding support - Start */
 | 
						|
+struct bond_cb __rcu *bond_cb;
 | 
						|
+
 | 
						|
+int bond_register_cb(struct bond_cb *cb)
 | 
						|
+{
 | 
						|
+	struct bond_cb *lag_cb;
 | 
						|
+
 | 
						|
+	lag_cb = kzalloc(sizeof(*lag_cb), GFP_ATOMIC | __GFP_NOWARN);
 | 
						|
+	if (!lag_cb) {
 | 
						|
+		return -1;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	memcpy((void *)lag_cb, (void *)cb, sizeof(*cb));
 | 
						|
+
 | 
						|
+	rcu_read_lock();
 | 
						|
+	rcu_assign_pointer(bond_cb, lag_cb);
 | 
						|
+	rcu_read_unlock();
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+EXPORT_SYMBOL(bond_register_cb);
 | 
						|
+
 | 
						|
+void bond_unregister_cb(void)
 | 
						|
+{
 | 
						|
+	struct bond_cb *lag_cb_main;
 | 
						|
+
 | 
						|
+	rcu_read_lock();
 | 
						|
+	lag_cb_main = rcu_dereference(bond_cb);
 | 
						|
+	rcu_assign_pointer(bond_cb, NULL);
 | 
						|
+	rcu_read_unlock();
 | 
						|
+
 | 
						|
+	kfree(lag_cb_main);
 | 
						|
+}
 | 
						|
+EXPORT_SYMBOL(bond_unregister_cb);
 | 
						|
+/* QCA NSS ECM bonding support - End */
 | 
						|
 
 | 
						|
 /* ================= api to bonding and kernel code ================== */
 | 
						|
 
 | 
						|
@@ -1073,7 +1107,31 @@ static void ad_mux_machine(struct port *
 | 
						|
 			ad_disable_collecting_distributing(port,
 | 
						|
 							   update_slave_arr);
 | 
						|
 			port->ntt = true;
 | 
						|
+
 | 
						|
+		/* QCA NSS ECM bonding support - Start */
 | 
						|
+			/* Send a notificaton about change in state of this
 | 
						|
+			* port. We only want to handle case where port moves
 | 
						|
+			* from AD_MUX_COLLECTING_DISTRIBUTING ->
 | 
						|
+			* AD_MUX_ATTACHED.
 | 
						|
+			*/
 | 
						|
+			if (bond_slave_is_up(port->slave) &&
 | 
						|
+			    (last_state == AD_MUX_COLLECTING_DISTRIBUTING)) {
 | 
						|
+				struct bond_cb *lag_cb_main;
 | 
						|
+
 | 
						|
+				rcu_read_lock();
 | 
						|
+				lag_cb_main = rcu_dereference(bond_cb);
 | 
						|
+				if (lag_cb_main &&
 | 
						|
+				    lag_cb_main->bond_cb_link_down) {
 | 
						|
+					struct net_device *dev;
 | 
						|
+
 | 
						|
+					dev = port->slave->dev;
 | 
						|
+					lag_cb_main->bond_cb_link_down(dev);
 | 
						|
+				}
 | 
						|
+				rcu_read_unlock();
 | 
						|
+			}
 | 
						|
+
 | 
						|
 			break;
 | 
						|
+		/* QCA NSS ECM bonding support - End */
 | 
						|
 		case AD_MUX_COLLECTING_DISTRIBUTING:
 | 
						|
 			port->actor_oper_port_state |= LACP_STATE_COLLECTING;
 | 
						|
 			port->actor_oper_port_state |= LACP_STATE_DISTRIBUTING;
 | 
						|
@@ -1917,6 +1975,7 @@ static void ad_enable_collecting_distrib
 | 
						|
 					      bool *update_slave_arr)
 | 
						|
 {
 | 
						|
 	if (port->aggregator->is_active) {
 | 
						|
+		struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */
 | 
						|
 		slave_dbg(port->slave->bond->dev, port->slave->dev,
 | 
						|
 			  "Enabling port %d (LAG %d)\n",
 | 
						|
 			  port->actor_port_number,
 | 
						|
@@ -1924,6 +1983,16 @@ static void ad_enable_collecting_distrib
 | 
						|
 		__enable_port(port);
 | 
						|
 		/* Slave array needs update */
 | 
						|
 		*update_slave_arr = true;
 | 
						|
+
 | 
						|
+		/* QCA NSS ECM bonding support - Start */
 | 
						|
+		rcu_read_lock();
 | 
						|
+		lag_cb_main = rcu_dereference(bond_cb);
 | 
						|
+
 | 
						|
+		if (lag_cb_main && lag_cb_main->bond_cb_link_up)
 | 
						|
+			lag_cb_main->bond_cb_link_up(port->slave->dev);
 | 
						|
+
 | 
						|
+		rcu_read_unlock();
 | 
						|
+		/* QCA NSS ECM bonding support - End */
 | 
						|
 	}
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -2683,6 +2752,104 @@ int bond_3ad_get_active_agg_info(struct
 | 
						|
 	return ret;
 | 
						|
 }
 | 
						|
 
 | 
						|
+/* QCA NSS ECM bonding support - Start */
 | 
						|
+/* bond_3ad_get_tx_dev - Calculate egress interface for a given packet,
 | 
						|
+ * for a LAG that is configured in 802.3AD mode
 | 
						|
+ * @skb: pointer to skb to be egressed
 | 
						|
+ * @src_mac: pointer to source L2 address
 | 
						|
+ * @dst_mac: pointer to destination L2 address
 | 
						|
+ * @src: pointer to source L3 address
 | 
						|
+ * @dst: pointer to destination L3 address
 | 
						|
+ * @protocol: L3 protocol id from L2 header
 | 
						|
+ * @bond_dev: pointer to bond master device
 | 
						|
+ *
 | 
						|
+ * If @skb is NULL, bond_xmit_hash is used to calculate hash using L2/L3
 | 
						|
+ * addresses.
 | 
						|
+ *
 | 
						|
+ * Returns: Either valid slave device, or NULL otherwise
 | 
						|
+ */
 | 
						|
+struct net_device *bond_3ad_get_tx_dev(struct sk_buff *skb, u8 *src_mac,
 | 
						|
+				       u8 *dst_mac, void *src,
 | 
						|
+				       void *dst, u16 protocol,
 | 
						|
+				       struct net_device *bond_dev,
 | 
						|
+				       __be16 *layer4hdr)
 | 
						|
+{
 | 
						|
+	struct bonding *bond = netdev_priv(bond_dev);
 | 
						|
+	struct aggregator *agg;
 | 
						|
+	struct ad_info ad_info;
 | 
						|
+	struct list_head *iter;
 | 
						|
+	struct slave *slave;
 | 
						|
+	struct slave *first_ok_slave = NULL;
 | 
						|
+	u32 hash = 0;
 | 
						|
+	int slaves_in_agg;
 | 
						|
+	int slave_agg_no = 0;
 | 
						|
+	int agg_id;
 | 
						|
+
 | 
						|
+	if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
 | 
						|
+		pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n",
 | 
						|
+			 bond_dev->name);
 | 
						|
+		return NULL;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	slaves_in_agg = ad_info.ports;
 | 
						|
+	agg_id = ad_info.aggregator_id;
 | 
						|
+
 | 
						|
+	if (slaves_in_agg == 0) {
 | 
						|
+		pr_debug("%s: Error: active aggregator is empty\n",
 | 
						|
+			 bond_dev->name);
 | 
						|
+		return NULL;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (skb) {
 | 
						|
+		hash = bond_xmit_hash(bond, skb);
 | 
						|
+		slave_agg_no = hash % slaves_in_agg;
 | 
						|
+	} else {
 | 
						|
+		if (bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER23 &&
 | 
						|
+		    bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER2 &&
 | 
						|
+		    bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER34) {
 | 
						|
+			pr_debug("%s: Error: Unsupported hash policy for 802.3AD fast path\n",
 | 
						|
+				 bond_dev->name);
 | 
						|
+			return NULL;
 | 
						|
+		}
 | 
						|
+
 | 
						|
+		hash = bond_xmit_hash_without_skb(src_mac, dst_mac,
 | 
						|
+						  src, dst, protocol,
 | 
						|
+						  bond_dev, layer4hdr);
 | 
						|
+		slave_agg_no = hash % slaves_in_agg;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	bond_for_each_slave_rcu(bond, slave, iter) {
 | 
						|
+		agg = SLAVE_AD_INFO(slave)->port.aggregator;
 | 
						|
+		if (!agg || agg->aggregator_identifier != agg_id)
 | 
						|
+			continue;
 | 
						|
+
 | 
						|
+		if (slave_agg_no >= 0) {
 | 
						|
+			if (!first_ok_slave && bond_slave_can_tx(slave))
 | 
						|
+				first_ok_slave = slave;
 | 
						|
+			slave_agg_no--;
 | 
						|
+			continue;
 | 
						|
+		}
 | 
						|
+
 | 
						|
+		if (bond_slave_can_tx(slave))
 | 
						|
+			return slave->dev;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (slave_agg_no >= 0) {
 | 
						|
+		pr_err("%s: Error: Couldn't find a slave to tx on for aggregator ID %d\n",
 | 
						|
+		       bond_dev->name, agg_id);
 | 
						|
+		return NULL;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	/* we couldn't find any suitable slave after the agg_no, so use the
 | 
						|
+	 * first suitable found, if found.
 | 
						|
+	 */
 | 
						|
+	if (first_ok_slave)
 | 
						|
+		return first_ok_slave->dev;
 | 
						|
+
 | 
						|
+	return NULL;
 | 
						|
+}
 | 
						|
+/* QCA NSS ECM bonding support - End */
 | 
						|
+
 | 
						|
 int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
 | 
						|
 			 struct slave *slave)
 | 
						|
 {
 | 
						|
--- a/drivers/net/bonding/bond_main.c
 | 
						|
+++ b/drivers/net/bonding/bond_main.c
 | 
						|
@@ -288,6 +288,21 @@ const char *bond_mode_name(int mode)
 | 
						|
 	return names[mode];
 | 
						|
 }
 | 
						|
 
 | 
						|
+/* QCA NSS ECM bonding support */
 | 
						|
+int bond_get_id(struct net_device *bond_dev)
 | 
						|
+{
 | 
						|
+	struct bonding *bond;
 | 
						|
+
 | 
						|
+	if (!((bond_dev->priv_flags & IFF_BONDING) &&
 | 
						|
+	      (bond_dev->flags & IFF_MASTER)))
 | 
						|
+		return -EINVAL;
 | 
						|
+
 | 
						|
+	bond = netdev_priv(bond_dev);
 | 
						|
+	return bond->id;
 | 
						|
+}
 | 
						|
+EXPORT_SYMBOL(bond_get_id);
 | 
						|
+/* QCA NSS ECM bonding support */
 | 
						|
+
 | 
						|
 /**
 | 
						|
  * bond_dev_queue_xmit - Prepare skb for xmit.
 | 
						|
  *
 | 
						|
@@ -1189,6 +1204,23 @@ void bond_change_active_slave(struct bon
 | 
						|
 			if (BOND_MODE(bond) == BOND_MODE_8023AD)
 | 
						|
 				bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
 | 
						|
 
 | 
						|
+           /* QCA NSS ECM bonding support - Start */
 | 
						|
+			if (bond->params.mode == BOND_MODE_XOR) {
 | 
						|
+				struct bond_cb *lag_cb_main;
 | 
						|
+
 | 
						|
+				rcu_read_lock();
 | 
						|
+				lag_cb_main = rcu_dereference(bond_cb);
 | 
						|
+				if (lag_cb_main &&
 | 
						|
+				    lag_cb_main->bond_cb_link_up) {
 | 
						|
+					struct net_device *dev;
 | 
						|
+
 | 
						|
+					dev = new_active->dev;
 | 
						|
+					lag_cb_main->bond_cb_link_up(dev);
 | 
						|
+				}
 | 
						|
+				rcu_read_unlock();
 | 
						|
+			}
 | 
						|
+           /* QCA NSS ECM bonding support - End */
 | 
						|
+
 | 
						|
 			if (bond_is_lb(bond))
 | 
						|
 				bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
 | 
						|
 		} else {
 | 
						|
@@ -1833,6 +1865,7 @@ int bond_enslave(struct net_device *bond
 | 
						|
 	const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 | 
						|
 	struct slave *new_slave = NULL, *prev_slave;
 | 
						|
 	struct sockaddr_storage ss;
 | 
						|
+	struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */
 | 
						|
 	int link_reporting;
 | 
						|
 	int res = 0, i;
 | 
						|
 
 | 
						|
@@ -2278,6 +2311,15 @@ int bond_enslave(struct net_device *bond
 | 
						|
 		   bond_is_active_slave(new_slave) ? "an active" : "a backup",
 | 
						|
 		   new_slave->link != BOND_LINK_DOWN ? "an up" : "a down");
 | 
						|
 
 | 
						|
+	/* QCA NSS ECM bonding support - Start */
 | 
						|
+	rcu_read_lock();
 | 
						|
+	lag_cb_main = rcu_dereference(bond_cb);
 | 
						|
+	if (lag_cb_main && lag_cb_main->bond_cb_enslave)
 | 
						|
+		lag_cb_main->bond_cb_enslave(slave_dev);
 | 
						|
+
 | 
						|
+	rcu_read_unlock();
 | 
						|
+	/* QCA NSS ECM bonding support - End */
 | 
						|
+
 | 
						|
 	/* enslave is successful */
 | 
						|
 	bond_queue_slave_event(new_slave);
 | 
						|
 	return 0;
 | 
						|
@@ -2343,6 +2385,15 @@ err_undo_flags:
 | 
						|
 		}
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	/* QCA NSS ECM bonding support - Start */
 | 
						|
+	rcu_read_lock();
 | 
						|
+	lag_cb_main = rcu_dereference(bond_cb);
 | 
						|
+	if (lag_cb_main && lag_cb_main->bond_cb_enslave)
 | 
						|
+		lag_cb_main->bond_cb_enslave(slave_dev);
 | 
						|
+
 | 
						|
+	rcu_read_unlock();
 | 
						|
+	/* QCA NSS ECM bonding support - End */
 | 
						|
+
 | 
						|
 	return res;
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -2364,6 +2415,7 @@ static int __bond_release_one(struct net
 | 
						|
 	struct bonding *bond = netdev_priv(bond_dev);
 | 
						|
 	struct slave *slave, *oldcurrent;
 | 
						|
 	struct sockaddr_storage ss;
 | 
						|
+	struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */
 | 
						|
 	int old_flags = bond_dev->flags;
 | 
						|
 	netdev_features_t old_features = bond_dev->features;
 | 
						|
 
 | 
						|
@@ -2386,6 +2438,15 @@ static int __bond_release_one(struct net
 | 
						|
 
 | 
						|
 	bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW);
 | 
						|
 
 | 
						|
+	/* QCA NSS ECM bonding support - Start */
 | 
						|
+	rcu_read_lock();
 | 
						|
+	lag_cb_main = rcu_dereference(bond_cb);
 | 
						|
+	if (lag_cb_main && lag_cb_main->bond_cb_release)
 | 
						|
+		lag_cb_main->bond_cb_release(slave_dev);
 | 
						|
+
 | 
						|
+	rcu_read_unlock();
 | 
						|
+	/* QCA NSS ECM bonding support - End */
 | 
						|
+
 | 
						|
 	bond_sysfs_slave_del(slave);
 | 
						|
 
 | 
						|
 	/* recompute stats just before removing the slave */
 | 
						|
@@ -2708,6 +2769,8 @@ static void bond_miimon_commit(struct bo
 | 
						|
 	struct slave *slave, *primary, *active;
 | 
						|
 	bool do_failover = false;
 | 
						|
 	struct list_head *iter;
 | 
						|
+	struct net_device *slave_dev = NULL; /* QCA NSS ECM bonding support */
 | 
						|
+	struct bond_cb *lag_cb_main; /* QCA NSS ECM bonding support */
 | 
						|
 
 | 
						|
 	ASSERT_RTNL();
 | 
						|
 
 | 
						|
@@ -2747,6 +2810,12 @@ static void bond_miimon_commit(struct bo
 | 
						|
 				bond_set_active_slave(slave);
 | 
						|
 			}
 | 
						|
 
 | 
						|
+			/* QCA NSS ECM bonding support - Start */
 | 
						|
+			if ((bond->params.mode == BOND_MODE_XOR) &&
 | 
						|
+			    (!slave_dev))
 | 
						|
+				slave_dev = slave->dev;
 | 
						|
+			/* QCA NSS ECM bonding support - End */
 | 
						|
+
 | 
						|
 			slave_info(bond->dev, slave->dev, "link status definitely up, %u Mbps %s duplex\n",
 | 
						|
 				   slave->speed == SPEED_UNKNOWN ? 0 : slave->speed,
 | 
						|
 				   slave->duplex ? "full" : "half");
 | 
						|
@@ -2795,6 +2864,16 @@ static void bond_miimon_commit(struct bo
 | 
						|
 		unblock_netpoll_tx();
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	/* QCA NSS ECM bonding support - Start */
 | 
						|
+	rcu_read_lock();
 | 
						|
+	lag_cb_main = rcu_dereference(bond_cb);
 | 
						|
+
 | 
						|
+	if (slave_dev && lag_cb_main && lag_cb_main->bond_cb_link_up)
 | 
						|
+		lag_cb_main->bond_cb_link_up(slave_dev);
 | 
						|
+
 | 
						|
+	rcu_read_unlock();
 | 
						|
+	/* QCA NSS ECM bonding support - End */
 | 
						|
+
 | 
						|
 	bond_set_carrier(bond);
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -4047,8 +4126,219 @@ static inline u32 bond_eth_hash(struct s
 | 
						|
 		return 0;
 | 
						|
 
 | 
						|
 	ep = (struct ethhdr *)(data + mhoff);
 | 
						|
-	return ep->h_dest[5] ^ ep->h_source[5] ^ be16_to_cpu(ep->h_proto);
 | 
						|
+	return ep->h_dest[5] ^ ep->h_source[5]; /* QCA NSS ECM bonding support */
 | 
						|
+}
 | 
						|
+
 | 
						|
+/* QCA NSS ECM bonding support - Start */
 | 
						|
+/* Extract the appropriate headers based on bond's xmit policy */
 | 
						|
+static bool bond_flow_dissect_without_skb(struct bonding *bond,
 | 
						|
+					  u8 *src_mac, u8 *dst_mac,
 | 
						|
+					  void *psrc, void *pdst,
 | 
						|
+					  u16 protocol, __be16 *layer4hdr,
 | 
						|
+					  struct flow_keys *fk)
 | 
						|
+{
 | 
						|
+	u32 *src = NULL;
 | 
						|
+	u32 *dst = NULL;
 | 
						|
+
 | 
						|
+	fk->ports.ports = 0;
 | 
						|
+	src = (uint32_t *)psrc;
 | 
						|
+	dst = (uint32_t *)pdst;
 | 
						|
+
 | 
						|
+	if (protocol == htons(ETH_P_IP)) {
 | 
						|
+       /* V4 addresses and address type*/
 | 
						|
+		fk->addrs.v4addrs.src = src[0];
 | 
						|
+		fk->addrs.v4addrs.dst = dst[0];
 | 
						|
+       fk->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
 | 
						|
+	} else if (protocol == htons(ETH_P_IPV6)) {
 | 
						|
+       /* V6 addresses and address type*/
 | 
						|
+		memcpy(&fk->addrs.v6addrs.src, src, sizeof(struct in6_addr));
 | 
						|
+		memcpy(&fk->addrs.v6addrs.dst, dst, sizeof(struct in6_addr));
 | 
						|
+       fk->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
 | 
						|
+	} else {
 | 
						|
+		return false;
 | 
						|
+	}
 | 
						|
+	if ((bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34) &&
 | 
						|
+	    (layer4hdr))
 | 
						|
+		fk->ports.ports = *layer4hdr;
 | 
						|
+
 | 
						|
+	return true;
 | 
						|
+}
 | 
						|
+
 | 
						|
+/* bond_xmit_hash_without_skb - Applies load balancing algorithm for a packet,
 | 
						|
+ * to calculate hash for a given set of L2/L3 addresses. Does not
 | 
						|
+ * calculate egress interface.
 | 
						|
+ */
 | 
						|
+uint32_t bond_xmit_hash_without_skb(u8 *src_mac, u8 *dst_mac,
 | 
						|
+				    void *psrc, void *pdst, u16 protocol,
 | 
						|
+				    struct net_device *bond_dev,
 | 
						|
+				    __be16 *layer4hdr)
 | 
						|
+{
 | 
						|
+	struct bonding *bond = netdev_priv(bond_dev);
 | 
						|
+	struct flow_keys flow;
 | 
						|
+	u32 hash = 0;
 | 
						|
+
 | 
						|
+	if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 ||
 | 
						|
+	    !bond_flow_dissect_without_skb(bond, src_mac, dst_mac, psrc,
 | 
						|
+					   pdst, protocol, layer4hdr, &flow))
 | 
						|
+		return (dst_mac[5] ^ src_mac[5]);
 | 
						|
+
 | 
						|
+	if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23)
 | 
						|
+		hash = dst_mac[5] ^ src_mac[5];
 | 
						|
+	else if (layer4hdr)
 | 
						|
+		hash = (__force u32)flow.ports.ports;
 | 
						|
+
 | 
						|
+	hash ^= (__force u32)flow_get_u32_dst(&flow) ^
 | 
						|
+		(__force u32)flow_get_u32_src(&flow);
 | 
						|
+	hash ^= (hash >> 16);
 | 
						|
+	hash ^= (hash >> 8);
 | 
						|
+
 | 
						|
+	return hash;
 | 
						|
+}
 | 
						|
+
 | 
						|
+/* bond_xor_get_tx_dev - Calculate egress interface for a given packet for a LAG
 | 
						|
+ * that is configured in balance-xor mode
 | 
						|
+ * @skb: pointer to skb to be egressed
 | 
						|
+ * @src_mac: pointer to source L2 address
 | 
						|
+ * @dst_mac: pointer to destination L2 address
 | 
						|
+ * @src: pointer to source L3 address in network order
 | 
						|
+ * @dst: pointer to destination L3 address in network order
 | 
						|
+ * @protocol: L3 protocol
 | 
						|
+ * @bond_dev: pointer to bond master device
 | 
						|
+ *
 | 
						|
+ * If @skb is NULL, bond_xmit_hash_without_skb is used to calculate hash using
 | 
						|
+ * L2/L3 addresses.
 | 
						|
+ *
 | 
						|
+ * Returns: Either valid slave device, or NULL otherwise
 | 
						|
+ */
 | 
						|
+static struct net_device *bond_xor_get_tx_dev(struct sk_buff *skb,
 | 
						|
+					      u8 *src_mac, u8 *dst_mac,
 | 
						|
+					      void *src, void *dst,
 | 
						|
+					      u16 protocol,
 | 
						|
+					      struct net_device *bond_dev,
 | 
						|
+					      __be16 *layer4hdr)
 | 
						|
+{
 | 
						|
+	struct bonding *bond = netdev_priv(bond_dev);
 | 
						|
+	int slave_cnt = READ_ONCE(bond->slave_cnt);
 | 
						|
+	int slave_id = 0, i = 0;
 | 
						|
+	u32 hash;
 | 
						|
+	struct list_head *iter;
 | 
						|
+	struct slave *slave;
 | 
						|
+
 | 
						|
+	if (slave_cnt == 0) {
 | 
						|
+		pr_debug("%s: Error: No slave is attached to the interface\n",
 | 
						|
+			 bond_dev->name);
 | 
						|
+		return NULL;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	if (skb) {
 | 
						|
+		hash = bond_xmit_hash(bond, skb);
 | 
						|
+		slave_id = hash % slave_cnt;
 | 
						|
+	} else {
 | 
						|
+		if (bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER23 &&
 | 
						|
+		    bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER2	&&
 | 
						|
+		    bond->params.xmit_policy != BOND_XMIT_POLICY_LAYER34) {
 | 
						|
+			pr_debug("%s: Error: Unsupported hash policy for balance-XOR fast path\n",
 | 
						|
+				 bond_dev->name);
 | 
						|
+			return NULL;
 | 
						|
+		}
 | 
						|
+
 | 
						|
+		hash = bond_xmit_hash_without_skb(src_mac, dst_mac, src,
 | 
						|
+						  dst, protocol, bond_dev,
 | 
						|
+						  layer4hdr);
 | 
						|
+		slave_id = hash % slave_cnt;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	i = slave_id;
 | 
						|
+
 | 
						|
+	/* Here we start from the slave with slave_id */
 | 
						|
+	bond_for_each_slave_rcu(bond, slave, iter) {
 | 
						|
+		if (--i < 0) {
 | 
						|
+			if (bond_slave_can_tx(slave))
 | 
						|
+				return slave->dev;
 | 
						|
+		}
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	/* Here we start from the first slave up to slave_id */
 | 
						|
+	i = slave_id;
 | 
						|
+	bond_for_each_slave_rcu(bond, slave, iter) {
 | 
						|
+		if (--i < 0)
 | 
						|
+			break;
 | 
						|
+		if (bond_slave_can_tx(slave))
 | 
						|
+			return slave->dev;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	return NULL;
 | 
						|
+}
 | 
						|
+
 | 
						|
+/* bond_get_tx_dev - Calculate egress interface for a given packet.
 | 
						|
+ *
 | 
						|
+ * Supports 802.3AD and balance-xor modes
 | 
						|
+ *
 | 
						|
+ * @skb: pointer to skb to be egressed, if valid
 | 
						|
+ * @src_mac: pointer to source L2 address
 | 
						|
+ * @dst_mac: pointer to destination L2 address
 | 
						|
+ * @src: pointer to source L3 address in network order
 | 
						|
+ * @dst: pointer to destination L3 address in network order
 | 
						|
+ * @protocol: L3 protocol id from L2 header
 | 
						|
+ * @bond_dev: pointer to bond master device
 | 
						|
+ *
 | 
						|
+ * Returns: Either valid slave device, or NULL for un-supported LAG modes
 | 
						|
+ */
 | 
						|
+struct net_device *bond_get_tx_dev(struct sk_buff *skb, uint8_t *src_mac,
 | 
						|
+				   u8 *dst_mac, void *src,
 | 
						|
+				   void *dst, u16 protocol,
 | 
						|
+				   struct net_device *bond_dev,
 | 
						|
+				   __be16 *layer4hdr)
 | 
						|
+{
 | 
						|
+	struct bonding *bond;
 | 
						|
+
 | 
						|
+	if (!bond_dev)
 | 
						|
+		return NULL;
 | 
						|
+
 | 
						|
+	if (!((bond_dev->priv_flags & IFF_BONDING) &&
 | 
						|
+	      (bond_dev->flags & IFF_MASTER)))
 | 
						|
+		return NULL;
 | 
						|
+
 | 
						|
+	bond = netdev_priv(bond_dev);
 | 
						|
+
 | 
						|
+	switch (bond->params.mode) {
 | 
						|
+	case BOND_MODE_XOR:
 | 
						|
+		return bond_xor_get_tx_dev(skb, src_mac, dst_mac,
 | 
						|
+					   src, dst, protocol,
 | 
						|
+					   bond_dev, layer4hdr);
 | 
						|
+	case BOND_MODE_8023AD:
 | 
						|
+		return bond_3ad_get_tx_dev(skb, src_mac, dst_mac,
 | 
						|
+					   src, dst, protocol,
 | 
						|
+					   bond_dev, layer4hdr);
 | 
						|
+	default:
 | 
						|
+		return NULL;
 | 
						|
+	}
 | 
						|
 }
 | 
						|
+EXPORT_SYMBOL(bond_get_tx_dev);
 | 
						|
+
 | 
						|
+/* In bond_xmit_xor() , we determine the output device by using a pre-
 | 
						|
+ * determined xmit_hash_policy(), If the selected device is not enabled,
 | 
						|
+ * find the next active slave.
 | 
						|
+ */
 | 
						|
+static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev)
 | 
						|
+{
 | 
						|
+	struct bonding *bond = netdev_priv(dev);
 | 
						|
+	struct net_device *outdev;
 | 
						|
+
 | 
						|
+	outdev = bond_xor_get_tx_dev(skb, NULL, NULL, NULL,
 | 
						|
+				     NULL, 0, dev, NULL);
 | 
						|
+	if (!outdev)
 | 
						|
+		goto out;
 | 
						|
+
 | 
						|
+	bond_dev_queue_xmit(bond, skb, outdev);
 | 
						|
+	goto final;
 | 
						|
+out:
 | 
						|
+	/* no suitable interface, frame not sent */
 | 
						|
+	dev_kfree_skb(skb);
 | 
						|
+final:
 | 
						|
+	return NETDEV_TX_OK;
 | 
						|
+}
 | 
						|
+/* QCA NSS ECM bonding support - End */
 | 
						|
 
 | 
						|
 static bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk, const void *data,
 | 
						|
 			 int hlen, __be16 l2_proto, int *nhoff, int *ip_proto, bool l34)
 | 
						|
@@ -5177,15 +5467,18 @@ static netdev_tx_t bond_3ad_xor_xmit(str
 | 
						|
 				     struct net_device *dev)
 | 
						|
 {
 | 
						|
 	struct bonding *bond = netdev_priv(dev);
 | 
						|
-	struct bond_up_slave *slaves;
 | 
						|
-	struct slave *slave;
 | 
						|
+	/* QCA NSS ECM bonding support - Start */
 | 
						|
+	struct net_device *outdev = NULL;
 | 
						|
 
 | 
						|
-	slaves = rcu_dereference(bond->usable_slaves);
 | 
						|
-	slave = bond_xmit_3ad_xor_slave_get(bond, skb, slaves);
 | 
						|
-	if (likely(slave))
 | 
						|
-		return bond_dev_queue_xmit(bond, skb, slave->dev);
 | 
						|
+	outdev = bond_3ad_get_tx_dev(skb, NULL, NULL, NULL,
 | 
						|
+				     NULL, 0, dev, NULL);
 | 
						|
+	if (!outdev) {
 | 
						|
+		dev_kfree_skb(skb);
 | 
						|
+		return NETDEV_TX_OK;
 | 
						|
+	}
 | 
						|
 
 | 
						|
-	return bond_tx_drop(dev, skb);
 | 
						|
+	return bond_dev_queue_xmit(bond, skb, outdev);
 | 
						|
+	/* QCA NSS ECM bonding support - End */
 | 
						|
 }
 | 
						|
 
 | 
						|
 /* in broadcast mode, we send everything to all usable interfaces. */
 | 
						|
@@ -5435,8 +5728,9 @@ static netdev_tx_t __bond_start_xmit(str
 | 
						|
 		return bond_xmit_roundrobin(skb, dev);
 | 
						|
 	case BOND_MODE_ACTIVEBACKUP:
 | 
						|
 		return bond_xmit_activebackup(skb, dev);
 | 
						|
-	case BOND_MODE_8023AD:
 | 
						|
 	case BOND_MODE_XOR:
 | 
						|
+		return bond_xmit_xor(skb, dev); /* QCA NSS ECM bonding support */
 | 
						|
+	case BOND_MODE_8023AD:
 | 
						|
 		return bond_3ad_xor_xmit(skb, dev);
 | 
						|
 	case BOND_MODE_BROADCAST:
 | 
						|
 		return bond_xmit_broadcast(skb, dev);
 | 
						|
--- a/include/net/bond_3ad.h
 | 
						|
+++ b/include/net/bond_3ad.h
 | 
						|
@@ -302,8 +302,15 @@ int bond_3ad_lacpdu_recv(const struct sk
 | 
						|
 			 struct slave *slave);
 | 
						|
 int bond_3ad_set_carrier(struct bonding *bond);
 | 
						|
 void bond_3ad_update_lacp_rate(struct bonding *bond);
 | 
						|
+/* QCA NSS ECM bonding support */
 | 
						|
+struct net_device *bond_3ad_get_tx_dev(struct sk_buff *skb, uint8_t *src_mac,
 | 
						|
+				       uint8_t *dst_mac, void *src,
 | 
						|
+				       void *dst, uint16_t protocol,
 | 
						|
+				       struct net_device *bond_dev,
 | 
						|
+				       __be16 *layer4hdr);
 | 
						|
+/* QCA NSS ECM bonding support */
 | 
						|
+
 | 
						|
 void bond_3ad_update_ad_actor_settings(struct bonding *bond);
 | 
						|
 int bond_3ad_stats_fill(struct sk_buff *skb, struct bond_3ad_stats *stats);
 | 
						|
 size_t bond_3ad_stats_size(void);
 | 
						|
 #endif /* _NET_BOND_3AD_H */
 | 
						|
-
 | 
						|
--- a/include/net/bonding.h
 | 
						|
+++ b/include/net/bonding.h
 | 
						|
@@ -90,6 +90,8 @@
 | 
						|
 #define BOND_XFRM_FEATURES (NETIF_F_HW_ESP | NETIF_F_HW_ESP_TX_CSUM | \
 | 
						|
 			    NETIF_F_GSO_ESP)
 | 
						|
 
 | 
						|
+extern struct bond_cb __rcu *bond_cb; /* QCA NSS ECM bonding support */
 | 
						|
+
 | 
						|
 #ifdef CONFIG_NET_POLL_CONTROLLER
 | 
						|
 extern atomic_t netpoll_block_tx;
 | 
						|
 
 | 
						|
@@ -653,6 +655,7 @@ struct bond_net {
 | 
						|
 
 | 
						|
 int bond_rcv_validate(const struct sk_buff *skb, struct bonding *bond, struct slave *slave);
 | 
						|
 netdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
 | 
						|
+int bond_get_id(struct net_device *bond_dev); /* QCA NSS ECM bonding support */
 | 
						|
 int bond_create(struct net *net, const char *name);
 | 
						|
 int bond_create_sysfs(struct bond_net *net);
 | 
						|
 void bond_destroy_sysfs(struct bond_net *net);
 | 
						|
@@ -684,6 +687,13 @@ struct bond_vlan_tag *bond_verify_device
 | 
						|
 					      int level);
 | 
						|
 int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave);
 | 
						|
 void bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay);
 | 
						|
+/* QCA NSS ECM bonding support - Start */
 | 
						|
+uint32_t bond_xmit_hash_without_skb(uint8_t *src_mac, uint8_t *dst_mac,
 | 
						|
+				    void *psrc, void *pdst, uint16_t protocol,
 | 
						|
+				    struct net_device *bond_dev,
 | 
						|
+				    __be16 *layer4hdr);
 | 
						|
+/* QCA NSS ECM bonding support - End */
 | 
						|
+
 | 
						|
 void bond_work_init_all(struct bonding *bond);
 | 
						|
 
 | 
						|
 #ifdef CONFIG_PROC_FS
 | 
						|
@@ -788,4 +798,18 @@ static inline netdev_tx_t bond_tx_drop(s
 | 
						|
 	return NET_XMIT_DROP;
 | 
						|
 }
 | 
						|
 
 | 
						|
+/* QCA NSS ECM bonding support - Start */
 | 
						|
+struct bond_cb {
 | 
						|
+	void (*bond_cb_link_up)(struct net_device *slave);
 | 
						|
+	void (*bond_cb_link_down)(struct net_device *slave);
 | 
						|
+	void (*bond_cb_enslave)(struct net_device *slave);
 | 
						|
+	void (*bond_cb_release)(struct net_device *slave);
 | 
						|
+	void (*bond_cb_delete_by_slave)(struct net_device *slave);
 | 
						|
+	void (*bond_cb_delete_by_mac)(uint8_t *mac_addr);
 | 
						|
+};
 | 
						|
+
 | 
						|
+extern int bond_register_cb(struct bond_cb *cb);
 | 
						|
+extern void bond_unregister_cb(void);
 | 
						|
+/* QCA NSS ECM bonding support - End */
 | 
						|
+
 | 
						|
 #endif /* _NET_BONDING_H */
 |