]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
IB/ipoib: Ignore L3 master device
authorVlad Dumitrescu <vdumitrescu@nvidia.com>
Tue, 16 Sep 2025 11:11:03 +0000 (14:11 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 13 Nov 2025 20:34:27 +0000 (15:34 -0500)
[ Upstream commit 42f993d3439827c4959ea77e60620d7ebfb3a477 ]

Currently, all master upper netdevices (e.g., bond, VRF) are treated
equally.

When a VRF netdevice is used over an IPoIB netdevice, the expected
netdev resolution is on the lower IPoIB device which has the IP address
assigned to it and not the VRF device.

The rdma_cm module (CMA) tries to match incoming requests to a
particular netdevice. When successful, it also validates that the return
path points to the same device by performing a routing table lookup.
Currently, the former would resolve to the VRF netdevice, while the
latter to the correct lower IPoIB netdevice, leading to failure in
rdma_cm.

Improve this by ignoring the VRF master netdevice, if it exists, and
instead return the lower IPoIB device.

Signed-off-by: Vlad Dumitrescu <vdumitrescu@nvidia.com>
Reviewed-by: Parav Pandit <parav@nvidia.com>
Signed-off-by: Edward Srouji <edwards@nvidia.com>
Link: https://patch.msgid.link/20250916111103.84069-5-edwards@nvidia.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/infiniband/ulp/ipoib/ipoib_main.c

index 4e31bb0b6466d93c6d3b1acb396d8126cb65d9a9..d65f3a59636514a38da4ffeefae1d78e6c2291da 100644 (file)
@@ -317,26 +317,27 @@ static bool ipoib_is_dev_match_addr_rcu(const struct sockaddr *addr,
 }
 
 /*
- * Find the master net_device on top of the given net_device.
+ * Find the L2 master net_device on top of the given net_device.
  * @dev: base IPoIB net_device
  *
- * Returns the master net_device with a reference held, or the same net_device
- * if no master exists.
+ * Returns the L2 master net_device with reference held if the L2 master
+ * exists (such as bond netdevice), or returns same netdev with reference
+ * held when master does not exist or when L3 master (such as VRF netdev).
  */
 static struct net_device *ipoib_get_master_net_dev(struct net_device *dev)
 {
        struct net_device *master;
 
        rcu_read_lock();
+
        master = netdev_master_upper_dev_get_rcu(dev);
+       if (!master || netif_is_l3_master(master))
+               master = dev;
+
        dev_hold(master);
        rcu_read_unlock();
 
-       if (master)
-               return master;
-
-       dev_hold(dev);
-       return dev;
+       return master;
 }
 
 struct ipoib_walk_data {
@@ -485,7 +486,7 @@ static struct net_device *ipoib_get_net_dev_by_params(
        if (ret)
                return NULL;
 
-       /* See if we can find a unique device matching the L2 parameters */
+       /* See if we can find a unique device matching the pkey and GID */
        matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index,
                                                gid, NULL, &net_dev);
 
@@ -498,7 +499,7 @@ static struct net_device *ipoib_get_net_dev_by_params(
 
        dev_put(net_dev);
 
-       /* Couldn't find a unique device with L2 parameters only. Use L3
+       /* Couldn't find a unique device with pkey and GID only. Use L3
         * address to uniquely match the net device */
        matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index,
                                                gid, addr, &net_dev);