Commit cbd09aeb authored by Moni Shoua's avatar Moni Shoua Committed by Doug Ledford

IB/core: Don't resolve IP address to the loopback device

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 abeffce9
("net/mlx5e: Fix a -Wmaybe-uninitialized warning") as a reference.
Signed-off-by: default avatarMoni Shoua <monis@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leon@kernel.org>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent bebb2a47
...@@ -268,6 +268,7 @@ int rdma_translate_ip(const struct sockaddr *addr, ...@@ -268,6 +268,7 @@ int rdma_translate_ip(const struct sockaddr *addr,
return ret; return ret;
ret = rdma_copy_addr(dev_addr, dev, NULL); ret = rdma_copy_addr(dev_addr, dev, NULL);
dev_addr->bound_dev_if = dev->ifindex;
if (vlan_id) if (vlan_id)
*vlan_id = rdma_vlan_dev_vlan_id(dev); *vlan_id = rdma_vlan_dev_vlan_id(dev);
dev_put(dev); dev_put(dev);
...@@ -280,6 +281,7 @@ int rdma_translate_ip(const struct sockaddr *addr, ...@@ -280,6 +281,7 @@ int rdma_translate_ip(const struct sockaddr *addr,
&((const struct sockaddr_in6 *)addr)->sin6_addr, &((const struct sockaddr_in6 *)addr)->sin6_addr,
dev, 1)) { dev, 1)) {
ret = rdma_copy_addr(dev_addr, dev, NULL); ret = rdma_copy_addr(dev_addr, dev, NULL);
dev_addr->bound_dev_if = dev->ifindex;
if (vlan_id) if (vlan_id)
*vlan_id = rdma_vlan_dev_vlan_id(dev); *vlan_id = rdma_vlan_dev_vlan_id(dev);
break; break;
...@@ -405,10 +407,10 @@ static int addr4_resolve(struct sockaddr_in *src_in, ...@@ -405,10 +407,10 @@ static int addr4_resolve(struct sockaddr_in *src_in,
fl4.saddr = src_ip; fl4.saddr = src_ip;
fl4.flowi4_oif = addr->bound_dev_if; fl4.flowi4_oif = addr->bound_dev_if;
rt = ip_route_output_key(addr->net, &fl4); rt = ip_route_output_key(addr->net, &fl4);
if (IS_ERR(rt)) { ret = PTR_ERR_OR_ZERO(rt);
ret = PTR_ERR(rt); if (ret)
goto out; return ret;
}
src_in->sin_family = AF_INET; src_in->sin_family = AF_INET;
src_in->sin_addr.s_addr = fl4.saddr; src_in->sin_addr.s_addr = fl4.saddr;
...@@ -423,8 +425,6 @@ static int addr4_resolve(struct sockaddr_in *src_in, ...@@ -423,8 +425,6 @@ static int addr4_resolve(struct sockaddr_in *src_in,
*prt = rt; *prt = rt;
return 0; return 0;
out:
return ret;
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
...@@ -527,8 +527,12 @@ static int addr_resolve(struct sockaddr *src_in, ...@@ -527,8 +527,12 @@ static int addr_resolve(struct sockaddr *src_in,
if (resolve_neigh) if (resolve_neigh)
ret = addr_resolve_neigh(&rt->dst, dst_in, addr, seq); ret = addr_resolve_neigh(&rt->dst, dst_in, addr, seq);
if (addr->bound_dev_if) {
ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
} else {
ndev = rt->dst.dev; ndev = rt->dst.dev;
dev_hold(ndev); dev_hold(ndev);
}
ip_rt_put(rt); ip_rt_put(rt);
} else { } else {
...@@ -544,13 +548,27 @@ static int addr_resolve(struct sockaddr *src_in, ...@@ -544,13 +548,27 @@ static int addr_resolve(struct sockaddr *src_in,
if (resolve_neigh) if (resolve_neigh)
ret = addr_resolve_neigh(dst, dst_in, addr, seq); ret = addr_resolve_neigh(dst, dst_in, addr, seq);
if (addr->bound_dev_if) {
ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
} else {
ndev = dst->dev; ndev = dst->dev;
dev_hold(ndev); dev_hold(ndev);
}
dst_release(dst); dst_release(dst);
} }
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; addr->bound_dev_if = ndev->ifindex;
}
dev_put(ndev); dev_put(ndev);
return ret; return ret;
......
...@@ -623,22 +623,11 @@ static inline int cma_validate_port(struct ib_device *device, u8 port, ...@@ -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)) if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port))
return ret; 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); ndev = dev_get_by_index(&init_net, bound_if_index);
if (ndev && ndev->flags & IFF_LOOPBACK) { else
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 {
gid_type = IB_GID_TYPE_IB; gid_type = IB_GID_TYPE_IB;
}
ret = ib_find_cached_gid_by_port(device, gid, gid_type, port, ret = ib_find_cached_gid_by_port(device, gid, gid_type, port,
ndev, NULL); ndev, NULL);
...@@ -2569,21 +2558,6 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv) ...@@ -2569,21 +2558,6 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
goto err2; 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, supported_gids = roce_gid_type_mask_support(id_priv->id.device,
id_priv->id.port_num); id_priv->id.port_num);
gid_type = cma_route_gid_type(addr->dev_addr.network, gid_type = cma_route_gid_type(addr->dev_addr.network,
......
...@@ -520,11 +520,6 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, ...@@ -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); 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(); rcu_read_lock();
if (resolved_dev != idev && !rdma_is_upper_dev_rcu(idev, if (resolved_dev != idev && !rdma_is_upper_dev_rcu(idev,
resolved_dev)) resolved_dev))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment