forked from mirrors/linux
		
	RDMA/core Introduce and use rdma_find_ndev_for_src_ip_rcu
This fixes two issues: 1. When address family is other than IPv4 or v6, rdma_translate_ip() returns success which is incorrect. 2. When address familty is AF_INET6, and if the source address is not found, it returns success, which is also incorrect. Therefore, introduce and use rdma_find_ndev_for_src_ip_rcu() helper function which returns correct success or error status and is also useful for future code refactor in addr_resolve(). Signed-off-by: Parav Pandit <parav@mellanox.com> Reviewed-by: Daniel Jurgens <danielj@mellanox.com> Signed-off-by: Leon Romanovsky <leonro@mellanox.com> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
This commit is contained in:
		
							parent
							
								
									99ed748e87
								
							
						
					
					
						commit
						caf1e3ae9f
					
				
					 1 changed files with 35 additions and 26 deletions
				
			
		| 
						 | 
				
			
			@ -232,6 +232,36 @@ void rdma_copy_addr(struct rdma_dev_addr *dev_addr,
 | 
			
		|||
}
 | 
			
		||||
EXPORT_SYMBOL(rdma_copy_addr);
 | 
			
		||||
 | 
			
		||||
static struct net_device *
 | 
			
		||||
rdma_find_ndev_for_src_ip_rcu(struct net *net, const struct sockaddr *src_in)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *dev = NULL;
 | 
			
		||||
	int ret = -EADDRNOTAVAIL;
 | 
			
		||||
 | 
			
		||||
	switch (src_in->sa_family) {
 | 
			
		||||
	case AF_INET:
 | 
			
		||||
		dev = __ip_dev_find(net,
 | 
			
		||||
				    ((const struct sockaddr_in *)src_in)->sin_addr.s_addr,
 | 
			
		||||
				    false);
 | 
			
		||||
		if (dev)
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		break;
 | 
			
		||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
			
		||||
	case AF_INET6:
 | 
			
		||||
		for_each_netdev_rcu(net, dev) {
 | 
			
		||||
			if (ipv6_chk_addr(net,
 | 
			
		||||
					  &((const struct sockaddr_in6 *)src_in)->sin6_addr,
 | 
			
		||||
					  dev, 1)) {
 | 
			
		||||
				ret = 0;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
	return ret ? ERR_PTR(ret) : dev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rdma_translate_ip(const struct sockaddr *addr,
 | 
			
		||||
		      struct rdma_dev_addr *dev_addr)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -246,33 +276,12 @@ int rdma_translate_ip(const struct sockaddr *addr,
 | 
			
		|||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (addr->sa_family) {
 | 
			
		||||
	case AF_INET:
 | 
			
		||||
		dev = ip_dev_find(dev_addr->net,
 | 
			
		||||
			((const struct sockaddr_in *)addr)->sin_addr.s_addr);
 | 
			
		||||
 | 
			
		||||
		if (!dev)
 | 
			
		||||
			return -EADDRNOTAVAIL;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	dev = rdma_find_ndev_for_src_ip_rcu(dev_addr->net, addr);
 | 
			
		||||
	if (!IS_ERR(dev))
 | 
			
		||||
		rdma_copy_addr(dev_addr, dev, NULL);
 | 
			
		||||
		dev_put(dev);
 | 
			
		||||
		break;
 | 
			
		||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
			
		||||
	case AF_INET6:
 | 
			
		||||
		rcu_read_lock();
 | 
			
		||||
		for_each_netdev_rcu(dev_addr->net, dev) {
 | 
			
		||||
			if (ipv6_chk_addr(dev_addr->net,
 | 
			
		||||
					  &((const struct sockaddr_in6 *)addr)->sin6_addr,
 | 
			
		||||
					  dev, 1)) {
 | 
			
		||||
				rdma_copy_addr(dev_addr, dev, NULL);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		rcu_read_unlock();
 | 
			
		||||
		break;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	return PTR_ERR_OR_ZERO(dev);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(rdma_translate_ip);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue