IB/core: Don't resolve IP address to the loopback device
authorMoni Shoua <monis@mellanox.com>
Tue, 23 May 2017 07:48:45 +0000 (10:48 +0300)
committerDoug Ledford <dledford@redhat.com>
Mon, 17 Jul 2017 15:45:42 +0000 (11:45 -0400)
When resolving an IP address that is on the host of the caller the
result from querying the routing table is the loopback device. This is
not a valid response, because it doesn't represent the RDMA device and
the port.

Therefore, callers need to check the resolved device and if it is a
loopback device find an alternative way to resolve it. To avoid this we
make sure that the response from rdma_resolve_ip() will not be the
loopback device.

While that, we fix an static checker warning about dereferencing an
unintitialized pointer using the same solution as in commit abeffce90c7f
("net/mlx5e: Fix a -Wmaybe-uninitialized warning") as a reference.

Signed-off-by: Moni Shoua <monis@mellanox.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/core/addr.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/verbs.c

index d78bc74..01236ce 100644 (file)
@@ -268,6 +268,7 @@ int rdma_translate_ip(const struct sockaddr *addr,
                        return ret;
 
                ret = rdma_copy_addr(dev_addr, dev, NULL);
+               dev_addr->bound_dev_if = dev->ifindex;
                if (vlan_id)
                        *vlan_id = rdma_vlan_dev_vlan_id(dev);
                dev_put(dev);
@@ -280,6 +281,7 @@ int rdma_translate_ip(const struct sockaddr *addr,
                                          &((const struct sockaddr_in6 *)addr)->sin6_addr,
                                          dev, 1)) {
                                ret = rdma_copy_addr(dev_addr, dev, NULL);
+                               dev_addr->bound_dev_if = dev->ifindex;
                                if (vlan_id)
                                        *vlan_id = rdma_vlan_dev_vlan_id(dev);
                                break;
@@ -405,10 +407,10 @@ static int addr4_resolve(struct sockaddr_in *src_in,
        fl4.saddr = src_ip;
        fl4.flowi4_oif = addr->bound_dev_if;
        rt = ip_route_output_key(addr->net, &fl4);
-       if (IS_ERR(rt)) {
-               ret = PTR_ERR(rt);
-               goto out;
-       }
+       ret = PTR_ERR_OR_ZERO(rt);
+       if (ret)
+               return ret;
+
        src_in->sin_family = AF_INET;
        src_in->sin_addr.s_addr = fl4.saddr;
 
@@ -423,8 +425,6 @@ static int addr4_resolve(struct sockaddr_in *src_in,
 
        *prt = rt;
        return 0;
-out:
-       return ret;
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -527,8 +527,12 @@ static int addr_resolve(struct sockaddr *src_in,
                if (resolve_neigh)
                        ret = addr_resolve_neigh(&rt->dst, dst_in, addr, seq);
 
-               ndev = rt->dst.dev;
-               dev_hold(ndev);
+               if (addr->bound_dev_if) {
+                       ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
+               } else {
+                       ndev = rt->dst.dev;
+                       dev_hold(ndev);
+               }
 
                ip_rt_put(rt);
        } else {
@@ -544,13 +548,27 @@ static int addr_resolve(struct sockaddr *src_in,
                if (resolve_neigh)
                        ret = addr_resolve_neigh(dst, dst_in, addr, seq);
 
-               ndev = dst->dev;
-               dev_hold(ndev);
+               if (addr->bound_dev_if) {
+                       ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
+               } else {
+                       ndev = dst->dev;
+                       dev_hold(ndev);
+               }
 
                dst_release(dst);
        }
 
-       addr->bound_dev_if = ndev->ifindex;
+       if (ndev->flags & IFF_LOOPBACK) {
+               ret = rdma_translate_ip(dst_in, addr, NULL);
+               /*
+                * Put the loopback device and get the translated
+                * device instead.
+                */
+               dev_put(ndev);
+               ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
+       } else {
+               addr->bound_dev_if = ndev->ifindex;
+       }
        dev_put(ndev);
 
        return ret;
index 31bb82d..11aff92 100644 (file)
@@ -623,22 +623,11 @@ static inline int cma_validate_port(struct ib_device *device, u8 port,
        if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port))
                return ret;
 
-       if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) {
+       if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port))
                ndev = dev_get_by_index(&init_net, bound_if_index);
-               if (ndev && ndev->flags & IFF_LOOPBACK) {
-                       pr_info("detected loopback device\n");
-                       dev_put(ndev);
-
-                       if (!device->get_netdev)
-                               return -EOPNOTSUPP;
-
-                       ndev = device->get_netdev(device, port);
-                       if (!ndev)
-                               return -ENODEV;
-               }
-       } else {
+       else
                gid_type = IB_GID_TYPE_IB;
-       }
+
 
        ret = ib_find_cached_gid_by_port(device, gid, gid_type, port,
                                         ndev, NULL);
@@ -2569,21 +2558,6 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
                        goto err2;
                }
 
-               if (ndev->flags & IFF_LOOPBACK) {
-                       dev_put(ndev);
-                       if (!id_priv->id.device->get_netdev) {
-                               ret = -EOPNOTSUPP;
-                               goto err2;
-                       }
-
-                       ndev = id_priv->id.device->get_netdev(id_priv->id.device,
-                                                             id_priv->id.port_num);
-                       if (!ndev) {
-                               ret = -ENODEV;
-                               goto err2;
-                       }
-               }
-
                supported_gids = roce_gid_type_mask_support(id_priv->id.device,
                                                            id_priv->id.port_num);
                gid_type = cma_route_gid_type(addr->dev_addr.network,
index 47ee1f8..644fa0d 100644 (file)
@@ -520,11 +520,6 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num,
                }
 
                resolved_dev = dev_get_by_index(&init_net, if_index);
-               if (resolved_dev->flags & IFF_LOOPBACK) {
-                       dev_put(resolved_dev);
-                       resolved_dev = idev;
-                       dev_hold(resolved_dev);
-               }
                rcu_read_lock();
                if (resolved_dev != idev && !rdma_is_upper_dev_rcu(idev,
                                                                   resolved_dev))