diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b4351ca..4b53733 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3759,6 +3759,101 @@ err:
 	bond_slave_arr_work_rearm(bond, 1);
 }
 
+static int slave_present(struct slave *slave, struct bond_up_slave *arr)
+{
+	int i;
+
+	if (!arr)
+		return 0;
+
+	for (i = 0; i < arr->count; i++) {
+		if (arr->arr[i] == slave)
+			return 1;
+	}
+	return 0;
+}
+
+/* Send notification to clear/remove slaves for 'bond' in 'arr' except for
+ * slaves in 'ignore_arr'.
+ */
+static int bond_slave_arr_clear_notify(struct bonding *bond,
+				struct bond_up_slave *arr,
+				struct bond_up_slave *ignore_arr)
+{
+	struct slave *slave;
+	struct net_device *slave_dev;
+	int i, rv;
+	const struct net_device_ops *ops;
+
+	if (!bond->dev || !arr)
+		return -EINVAL;
+
+	rv = 0;
+	for (i = 0; i < arr->count; i++) {
+		slave = arr->arr[i];
+		if (!slave || !slave->dev)
+			continue;
+
+		slave_dev = slave->dev;
+		if (slave_present(slave, ignore_arr)) {
+			netdev_dbg(bond->dev, "ignoring clear of slave %s\n",
+				slave_dev->name);
+			continue;
+		}
+		ops = slave_dev->netdev_ops;
+		if (!ops || !ops->ndo_bond_slave_discard) {
+			netdev_dbg(bond->dev, "No slave discard ops for %s\n",
+				slave_dev->name);
+			continue;
+		}
+		rv = ops->ndo_bond_slave_discard(slave_dev, bond->dev);
+		if (rv < 0)
+			return rv;
+	}
+	return rv;
+}
+
+/* Send notification about updated slaves for 'bond' except for slaves in
+ * 'ignore_arr'.
+ */
+static int bond_slave_arr_set_notify(struct bonding *bond,
+				struct bond_up_slave *ignore_arr)
+{
+	struct slave *slave;
+	struct net_device *slave_dev;
+	struct bond_up_slave *arr;
+	int i, rv;
+	const struct net_device_ops *ops;
+
+	if (!bond || !bond->dev)
+		return -EINVAL;
+	rv = 0;
+
+	arr = rtnl_dereference(bond->slave_arr);
+	if (!arr)
+		return -EINVAL;
+
+	for (i = 0; i < arr->count; i++) {
+		slave = arr->arr[i];
+		slave_dev = slave->dev;
+		if (slave_present(slave, ignore_arr)) {
+			netdev_dbg(bond->dev, "ignoring add of slave %s\n",
+				slave->dev->name);
+			continue;
+		}
+		ops = slave_dev->netdev_ops;
+		if (!ops || !ops->ndo_bond_slave_add) {
+			netdev_dbg(bond->dev, "No slave add ops for %s\n",
+				slave_dev->name);
+			continue;
+		}
+		rv = ops->ndo_bond_slave_add(slave_dev, bond->dev);
+		if (rv < 0)
+			return rv;
+	}
+	return rv;
+}
+
 /* Build the usable slaves array in control path for modes that use xmit-hash
  * to determine the slave interface -
  * (a) BOND_MODE_8023AD
@@ -3771,7 +3866,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
 {
 	struct slave *slave;
 	struct list_head *iter;
-	struct bond_up_slave *new_arr, *old_arr;
+	struct bond_up_slave *new_arr, *old_arr, *discard_arr = 0;
 	int agg_id = 0;
 	int ret = 0;
 
@@ -3786,6 +3881,12 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
 		pr_err("Failed to build slave-array.\n");
 		goto out;
 	}
+	discard_arr = kzalloc(offsetof(struct bond_up_slave, arr[bond->slave_cnt]),
+			GFP_KERNEL);
+	if (!discard_arr) {
+		ret = -ENOMEM;
+		goto out;
+	}
 	if (BOND_MODE(bond) == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
 
@@ -3797,6 +3898,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
 			 */
 			old_arr = rtnl_dereference(bond->slave_arr);
 			if (old_arr) {
+				bond_slave_arr_clear_notify(bond, old_arr, 0);
 				RCU_INIT_POINTER(bond->slave_arr, NULL);
 				kfree_rcu(old_arr, rcu);
 			}
@@ -3809,8 +3911,10 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
 			struct aggregator *agg;
 
 			agg = SLAVE_AD_INFO(slave)->port.aggregator;
-			if (!agg || agg->aggregator_identifier != agg_id)
+			if (!agg || agg->aggregator_identifier != agg_id) {
+				discard_arr->arr[discard_arr->count++] = slave;
 				continue;
+			}
 		}
 		if (!bond_slave_can_tx(slave))
 			continue;
@@ -3820,10 +3924,15 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
 	}
 
 	old_arr = rtnl_dereference(bond->slave_arr);
+	bond_slave_arr_clear_notify(bond, old_arr, new_arr);
+	bond_slave_arr_clear_notify(bond, discard_arr, 0);
 	rcu_assign_pointer(bond->slave_arr, new_arr);
+	bond_slave_arr_set_notify(bond, old_arr);
 	if (old_arr)
 		kfree_rcu(old_arr, rcu);
 out:
+	if (discard_arr)
+		kfree(discard_arr);
 	if (ret != 0 && skipslave) {
 		int idx;
 
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4ac653b..facc35f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1236,6 +1236,10 @@ struct net_device_ops {
 							 bool proto_down);
 	int			(*ndo_fill_metadata_dst)(struct net_device *dev,
 						       struct sk_buff *skb);
+	int		(*ndo_bond_slave_add)(struct net_device *slave_dev,
+				struct net_device *bond);
+	int		(*ndo_bond_slave_discard)(struct net_device *slave_dev,
+				struct net_device *bond);
 };
 
 /**
