@@ -37,6 +37,7 @@
/* For in6_dev_get/in6_dev_put */
#include <net/addrconf.h>
+#include <net/bonding.h>
#include <rdma/ib_cache.h>
#include <rdma/ib_addr.h>
@@ -127,12 +128,40 @@ static void update_gid(enum gid_op_type gid_op, struct ib_device *ib_dev,
}
}
+#define IS_NETDEV_BONDING_MASTER(ndev) \
+ (((ndev)->priv_flags & \
+ (IFF_BONDING | IFF_MASTER)) == (IFF_BONDING | IFF_MASTER))
+
+enum bonding_slave_state {
+ BONDING_SLAVE_STATE_ACTIVE,
+ BONDING_SLAVE_STATE_INACTIVE,
+ BONDING_SLAVE_STATE_NA
+};
+
+static enum bonding_slave_state is_eth_active_slave_of_bonding(struct net_device *idev,
+ struct net_device *upper)
+{
+ if (upper && IS_NETDEV_BONDING_MASTER(upper)) {
+ struct net_device *pdev;
+
+ rcu_read_lock();
+ pdev = bond_option_active_slave_get_rcu(netdev_priv(upper));
+ rcu_read_unlock();
+ if (pdev)
+ return idev == pdev ? BONDING_SLAVE_STATE_ACTIVE :
+ BONDING_SLAVE_STATE_INACTIVE;
+ }
+
+ return BONDING_SLAVE_STATE_NA;
+}
+
static int is_eth_port_of_netdev(struct ib_device *ib_dev, u8 port,
struct net_device *idev, void *cookie)
{
struct net_device *rdev;
struct net_device *mdev;
struct net_device *ndev = (struct net_device *)cookie;
+ int res;
if (!idev)
return 0;
@@ -140,9 +169,16 @@ static int is_eth_port_of_netdev(struct ib_device *ib_dev, u8 port,
rcu_read_lock();
mdev = netdev_master_upper_dev_get_rcu(idev);
rdev = rdma_vlan_dev_real_dev(ndev);
- rcu_read_unlock();
+ if (!rdev)
+ rdev = ndev;
- return (rdev ? rdev : ndev) == (mdev ? mdev : idev);
+ res = (rdev == idev ||
+ (rdev == mdev &&
+ is_eth_active_slave_of_bonding(idev, mdev) !=
+ BONDING_SLAVE_STATE_INACTIVE));
+
+ rcu_read_unlock();
+ return res;
}
static int pass_all_filter(struct ib_device *ib_dev, u8 port,
@@ -151,6 +187,26 @@ static int pass_all_filter(struct ib_device *ib_dev, u8 port,
return 1;
}
+static int bonding_slaves_filter(struct ib_device *ib_dev, u8 port,
+ struct net_device *idev, void *cookie)
+{
+ struct net_device *mdev;
+ struct net_device *rdev;
+ struct net_device *ndev = (struct net_device *)cookie;
+
+ rdev = rdma_vlan_dev_real_dev(ndev);
+
+ ndev = rdev ? rdev : ndev;
+ if (!idev || !IS_NETDEV_BONDING_MASTER(ndev))
+ return 0;
+
+ rcu_read_lock();
+ mdev = netdev_master_upper_dev_get_rcu(idev);
+ rcu_read_unlock();
+
+ return ndev == mdev;
+}
+
static void netdevice_event_work_handler(struct work_struct *_work)
{
struct netdev_event_work *work =
@@ -186,8 +242,16 @@ static void enum_netdev_default_gids(struct ib_device *ib_dev,
{
unsigned long gid_type_mask;
- if (idev != ndev)
+ rcu_read_lock();
+ if (!idev ||
+ ((idev != ndev && netdev_master_upper_dev_get_rcu(idev) != ndev) ||
+ is_eth_active_slave_of_bonding(idev,
+ netdev_master_upper_dev_get_rcu(idev)) ==
+ BONDING_SLAVE_STATE_INACTIVE)) {
+ rcu_read_unlock();
return;
+ }
+ rcu_read_unlock();
gid_type_mask = gid_type_mask_support(ib_dev, port);
@@ -195,6 +259,35 @@ static void enum_netdev_default_gids(struct ib_device *ib_dev,
ROCE_GID_CACHE_DEFAULT_MODE_SET);
}
+static void bond_delete_netdev_default_gids(struct ib_device *ib_dev,
+ u8 port, struct net_device *ndev,
+ struct net_device *idev)
+{
+ struct net_device *upper;
+
+ if (!idev)
+ return;
+
+ rcu_read_lock();
+ upper = netdev_master_upper_dev_get_rcu(idev);
+
+ if ((upper == ndev) &&
+ is_eth_active_slave_of_bonding(idev, upper) ==
+ BONDING_SLAVE_STATE_INACTIVE) {
+ unsigned long gid_type_mask;
+
+ rcu_read_unlock();
+
+ gid_type_mask = gid_type_mask_support(ib_dev, port);
+
+ roce_gid_cache_set_default_gid(ib_dev, port, idev,
+ gid_type_mask,
+ ROCE_GID_CACHE_DEFAULT_MODE_DELETE);
+ } else {
+ rcu_read_unlock();
+ }
+}
+
static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,
u8 port, struct net_device *ndev)
{
@@ -317,6 +410,27 @@ static void del_netdev_ips(struct ib_device *ib_dev, u8 port,
struct net_device *ndev = (struct net_device *)cookie;
roce_del_all_netdev_gids(ib_dev, port, ndev);
+ if (idev) {
+ bool is_upper;
+
+ rcu_read_lock();
+ is_upper = netdev_master_upper_dev_get_rcu(idev) == ndev;
+ rcu_read_unlock();
+
+ if (is_upper)
+ /* Delete default GIDs, vlans should be deleted
+ * first by user
+ */
+ roce_del_all_netdev_gids(ib_dev, port, idev);
+ }
+}
+
+static void del_netdev_default_ips(struct ib_device *ib_dev, u8 port,
+ struct net_device *idev, void *cookie)
+{
+ struct net_device *ndev = (struct net_device *)cookie;
+
+ bond_delete_netdev_default_gids(ib_dev, port, ndev, idev);
}
static int netdevice_event(struct notifier_block *this, unsigned long event,
@@ -326,6 +440,10 @@ static int netdevice_event(struct notifier_block *this, unsigned long event,
.cb = add_netdev_ips, .filter = is_eth_port_of_netdev};
static const struct netdev_event_work_cmd del_cmd = {
.cb = del_netdev_ips, .filter = pass_all_filter};
+ static const struct netdev_event_work_cmd bonding_default_del_cmd = {
+ .cb = del_netdev_default_ips, .filter = bonding_slaves_filter};
+ static const struct netdev_event_work_cmd bonding_ips_del_cmd = {
+ .cb = del_netdev_ips, .filter = bonding_slaves_filter};
struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
struct netdev_event_work *ndev_work;
struct netdev_event_work_cmd cmds[ROCE_NETDEV_CALLBACK_SZ] = { {NULL} };
@@ -336,7 +454,8 @@ static int netdevice_event(struct notifier_block *this, unsigned long event,
switch (event) {
case NETDEV_REGISTER:
case NETDEV_UP:
- cmds[0] = add_cmd;
+ cmds[0] = bonding_default_del_cmd;
+ cmds[1] = add_cmd;
break;
case NETDEV_UNREGISTER:
@@ -350,6 +469,16 @@ static int netdevice_event(struct notifier_block *this, unsigned long event,
cmds[0] = del_cmd;
cmds[1] = add_cmd;
break;
+
+ case NETDEV_BONDING_FAILOVER:
+ cmds[0] = bonding_ips_del_cmd;
+ cmds[1] = add_cmd;
+ break;
+ case NETDEV_JOIN:
+ cmds[0] = bonding_default_del_cmd;
+ cmds[1] = add_cmd;
+ break;
+
default:
return NOTIFY_DONE;
}
@@ -690,19 +690,6 @@ static int bond_option_mode_set(struct bonding *bond,
return 0;
}
-static struct net_device *__bond_option_active_slave_get(struct bonding *bond,
- struct slave *slave)
-{
- return bond_uses_primary(bond) && slave ? slave->dev : NULL;
-}
-
-struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond)
-{
- struct slave *slave = rcu_dereference(bond->curr_active_slave);
-
- return __bond_option_active_slave_get(bond, slave);
-}
-
static int bond_option_active_slave_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
@@ -314,6 +314,13 @@ static inline bool bond_uses_primary(struct bonding *bond)
return bond_mode_uses_primary(BOND_MODE(bond));
}
+static inline struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond)
+{
+ struct slave *slave = rcu_dereference(bond->curr_active_slave);
+
+ return bond_uses_primary(bond) && slave ? slave->dev : NULL;
+}
+
static inline bool bond_slave_is_up(struct slave *slave)
{
return netif_running(slave->dev) && netif_carrier_ok(slave->dev);