IB/core: Fix deleting default GIDs when changing mac adddress
authorParav Pandit <parav@mellanox.com>
Mon, 23 Apr 2018 13:58:19 +0000 (16:58 +0300)
committerDoug Ledford <dledford@redhat.com>
Mon, 23 Apr 2018 21:28:18 +0000 (17:28 -0400)
Before [1], When MAC address of the netdevice is changed, default GID is
supposed to get deleted and added back which affects the node and/or port
GUID in below sequence.

netdevice_event()
-> NETDEV_CHANGEADDR
   default_del_cmd()
      del_netdev_default_ips()
          bond_delete_netdev_default_gids()
              ib_cache_gid_set_default_gid()
                  ib_cache_gid_del()
   add_cmd()
   [..]

However, ib_cache_gid_del() was not getting invoked in non bonding
scenarios because event_ndev and rdma_ndev are same.
Therefore, fix such condition to ignore checking upper device when event
ndev and rdma_dev are same; similar to bond_set_netdev_default_gids().

Which this fix ib_cache_gid_del() is invoked correctly; however
ib_cache_gid_del() doesn't find the default GID for deletion because
find_gid() was given default_gid = false with
GID_ATTR_FIND_MASK_DEFAULT set.
But it was getting overwritten by ib_cache_gid_set_default_gid() later
on as part of add_cmd().
Therefore, mac address change used to work for default GID.

With refactor series [1], this incorrect behavior is detected.

Therefore,
when deleting default GID, set default_gid and set MASK flag.
when deleting IP based GID, clear default_gid and set MASK flag.

[1] https://patchwork.kernel.org/patch/10319151/

Fixes: 238fdf48f2b5 ("IB/core: Add RoCE table bonding support")
Fixes: 598ff6bae689 ("IB/core: Refactor GID modify code for RoCE")
Signed-off-by: Parav Pandit <parav@mellanox.com>
Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/core/cache.c
drivers/infiniband/core/roce_gid_mgmt.c

index 8e6a4f05f3eab3ba476da55485ce87f229f567b5..fb2d347f760f14c18e033f889732d58340dd8660 100644 (file)
@@ -427,7 +427,7 @@ int ib_cache_gid_add(struct ib_device *ib_dev, u8 port,
 static int
 _ib_cache_gid_del(struct ib_device *ib_dev, u8 port,
                  union ib_gid *gid, struct ib_gid_attr *attr,
-                 bool default_gid)
+                 unsigned long mask, bool default_gid)
 {
        struct ib_gid_table *table;
        int ret = 0;
@@ -437,12 +437,7 @@ _ib_cache_gid_del(struct ib_device *ib_dev, u8 port,
 
        mutex_lock(&table->lock);
 
-       ix = find_gid(table, gid, attr, default_gid,
-                     GID_ATTR_FIND_MASK_GID      |
-                     GID_ATTR_FIND_MASK_GID_TYPE |
-                     GID_ATTR_FIND_MASK_DEFAULT  |
-                     GID_ATTR_FIND_MASK_NETDEV,
-                     NULL);
+       ix = find_gid(table, gid, attr, default_gid, mask, NULL);
        if (ix < 0) {
                ret = -EINVAL;
                goto out_unlock;
@@ -462,7 +457,12 @@ out_unlock:
 int ib_cache_gid_del(struct ib_device *ib_dev, u8 port,
                     union ib_gid *gid, struct ib_gid_attr *attr)
 {
-       return _ib_cache_gid_del(ib_dev, port, gid, attr, false);
+       unsigned long mask = GID_ATTR_FIND_MASK_GID       |
+                            GID_ATTR_FIND_MASK_GID_TYPE |
+                            GID_ATTR_FIND_MASK_DEFAULT  |
+                            GID_ATTR_FIND_MASK_NETDEV;
+
+       return _ib_cache_gid_del(ib_dev, port, gid, attr, mask, false);
 }
 
 int ib_cache_gid_del_all_netdev_gids(struct ib_device *ib_dev, u8 port,
@@ -741,7 +741,7 @@ void ib_cache_gid_set_default_gid(struct ib_device *ib_dev, u8 port,
                                  unsigned long gid_type_mask,
                                  enum ib_cache_gid_default_mode mode)
 {
-       union ib_gid gid;
+       union ib_gid gid = { };
        struct ib_gid_attr gid_attr;
        struct ib_gid_table *table;
        unsigned int gid_type;
@@ -749,7 +749,9 @@ void ib_cache_gid_set_default_gid(struct ib_device *ib_dev, u8 port,
 
        table = ib_dev->cache.ports[port - rdma_start_port(ib_dev)].gid;
 
-       make_default_gid(ndev, &gid);
+       mask = GID_ATTR_FIND_MASK_GID_TYPE |
+              GID_ATTR_FIND_MASK_DEFAULT |
+              GID_ATTR_FIND_MASK_NETDEV;
        memset(&gid_attr, 0, sizeof(gid_attr));
        gid_attr.ndev = ndev;
 
@@ -760,12 +762,12 @@ void ib_cache_gid_set_default_gid(struct ib_device *ib_dev, u8 port,
                gid_attr.gid_type = gid_type;
 
                if (mode == IB_CACHE_GID_DEFAULT_MODE_SET) {
-                       mask = GID_ATTR_FIND_MASK_GID_TYPE |
-                              GID_ATTR_FIND_MASK_DEFAULT;
+                       make_default_gid(ndev, &gid);
                        __ib_cache_gid_add(ib_dev, port, &gid,
                                           &gid_attr, mask, true);
                } else if (mode == IB_CACHE_GID_DEFAULT_MODE_DELETE) {
-                       _ib_cache_gid_del(ib_dev, port, &gid, &gid_attr, true);
+                       _ib_cache_gid_del(ib_dev, port, &gid,
+                                         &gid_attr, mask, true);
                }
        }
 }
index cc2966380c0cab02f1f7bc1d0fc33c4d56c0b60b..c0e4fd55e2ccb77104b7a62cdde18440ab9c0f47 100644 (file)
@@ -255,6 +255,7 @@ static void bond_delete_netdev_default_gids(struct ib_device *ib_dev,
                                            struct net_device *rdma_ndev)
 {
        struct net_device *real_dev = rdma_vlan_dev_real_dev(event_ndev);
+       unsigned long gid_type_mask;
 
        if (!rdma_ndev)
                return;
@@ -264,21 +265,22 @@ static void bond_delete_netdev_default_gids(struct ib_device *ib_dev,
 
        rcu_read_lock();
 
-       if (rdma_is_upper_dev_rcu(rdma_ndev, event_ndev) &&
-           is_eth_active_slave_of_bonding_rcu(rdma_ndev, real_dev) ==
-           BONDING_SLAVE_STATE_INACTIVE) {
-               unsigned long gid_type_mask;
-
+       if (((rdma_ndev != event_ndev &&
+             !rdma_is_upper_dev_rcu(rdma_ndev, event_ndev)) ||
+            is_eth_active_slave_of_bonding_rcu(rdma_ndev, real_dev)
+                                                ==
+            BONDING_SLAVE_STATE_INACTIVE)) {
                rcu_read_unlock();
+               return;
+       }
 
-               gid_type_mask = roce_gid_type_mask_support(ib_dev, port);
+       rcu_read_unlock();
 
-               ib_cache_gid_set_default_gid(ib_dev, port, rdma_ndev,
-                                            gid_type_mask,
-                                            IB_CACHE_GID_DEFAULT_MODE_DELETE);
-       } else {
-               rcu_read_unlock();
-       }
+       gid_type_mask = roce_gid_type_mask_support(ib_dev, port);
+
+       ib_cache_gid_set_default_gid(ib_dev, port, rdma_ndev,
+                                    gid_type_mask,
+                                    IB_CACHE_GID_DEFAULT_MODE_DELETE);
 }
 
 static void enum_netdev_ipv4_ips(struct ib_device *ib_dev,