diff options
Diffstat (limited to 'drivers/infiniband/core/addr.c')
| -rw-r--r-- | drivers/infiniband/core/addr.c | 97 | 
1 files changed, 94 insertions, 3 deletions
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index e90f2b2eabd..8172d37f9ad 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -86,6 +86,8 @@ int rdma_addr_size(struct sockaddr *addr)  }  EXPORT_SYMBOL(rdma_addr_size); +static struct rdma_addr_client self; +  void rdma_addr_register_client(struct rdma_addr_client *client)  {  	atomic_set(&client->refcount, 1); @@ -119,7 +121,8 @@ int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,  }  EXPORT_SYMBOL(rdma_copy_addr); -int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) +int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr, +		      u16 *vlan_id)  {  	struct net_device *dev;  	int ret = -EADDRNOTAVAIL; @@ -142,6 +145,8 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)  			return ret;  		ret = rdma_copy_addr(dev_addr, dev, NULL); +		if (vlan_id) +			*vlan_id = rdma_vlan_dev_vlan_id(dev);  		dev_put(dev);  		break; @@ -153,6 +158,8 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)  					  &((struct sockaddr_in6 *) addr)->sin6_addr,  					  dev, 1)) {  				ret = rdma_copy_addr(dev_addr, dev, NULL); +				if (vlan_id) +					*vlan_id = rdma_vlan_dev_vlan_id(dev);  				break;  			}  		} @@ -238,7 +245,7 @@ static int addr4_resolve(struct sockaddr_in *src_in,  	src_in->sin_addr.s_addr = fl4.saddr;  	if (rt->dst.dev->flags & IFF_LOOPBACK) { -		ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); +		ret = rdma_translate_ip((struct sockaddr *)dst_in, addr, NULL);  		if (!ret)  			memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN);  		goto put; @@ -286,7 +293,7 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,  	}  	if (dst->dev->flags & IFF_LOOPBACK) { -		ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); +		ret = rdma_translate_ip((struct sockaddr *)dst_in, addr, NULL);  		if (!ret)  			memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN);  		goto put; @@ -437,6 +444,88 @@ void rdma_addr_cancel(struct rdma_dev_addr *addr)  }  EXPORT_SYMBOL(rdma_addr_cancel); +struct resolve_cb_context { +	struct rdma_dev_addr *addr; +	struct completion comp; +}; + +static void resolve_cb(int status, struct sockaddr *src_addr, +	     struct rdma_dev_addr *addr, void *context) +{ +	memcpy(((struct resolve_cb_context *)context)->addr, addr, sizeof(struct +				rdma_dev_addr)); +	complete(&((struct resolve_cb_context *)context)->comp); +} + +int rdma_addr_find_dmac_by_grh(union ib_gid *sgid, union ib_gid *dgid, u8 *dmac, +			       u16 *vlan_id) +{ +	int ret = 0; +	struct rdma_dev_addr dev_addr; +	struct resolve_cb_context ctx; +	struct net_device *dev; + +	union { +		struct sockaddr     _sockaddr; +		struct sockaddr_in  _sockaddr_in; +		struct sockaddr_in6 _sockaddr_in6; +	} sgid_addr, dgid_addr; + + +	ret = rdma_gid2ip(&sgid_addr._sockaddr, sgid); +	if (ret) +		return ret; + +	ret = rdma_gid2ip(&dgid_addr._sockaddr, dgid); +	if (ret) +		return ret; + +	memset(&dev_addr, 0, sizeof(dev_addr)); + +	ctx.addr = &dev_addr; +	init_completion(&ctx.comp); +	ret = rdma_resolve_ip(&self, &sgid_addr._sockaddr, &dgid_addr._sockaddr, +			&dev_addr, 1000, resolve_cb, &ctx); +	if (ret) +		return ret; + +	wait_for_completion(&ctx.comp); + +	memcpy(dmac, dev_addr.dst_dev_addr, ETH_ALEN); +	dev = dev_get_by_index(&init_net, dev_addr.bound_dev_if); +	if (!dev) +		return -ENODEV; +	if (vlan_id) +		*vlan_id = rdma_vlan_dev_vlan_id(dev); +	dev_put(dev); +	return ret; +} +EXPORT_SYMBOL(rdma_addr_find_dmac_by_grh); + +int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id) +{ +	int ret = 0; +	struct rdma_dev_addr dev_addr; +	union { +		struct sockaddr     _sockaddr; +		struct sockaddr_in  _sockaddr_in; +		struct sockaddr_in6 _sockaddr_in6; +	} gid_addr; + +	ret = rdma_gid2ip(&gid_addr._sockaddr, sgid); + +	if (ret) +		return ret; +	memset(&dev_addr, 0, sizeof(dev_addr)); +	ret = rdma_translate_ip(&gid_addr._sockaddr, &dev_addr, vlan_id); +	if (ret) +		return ret; + +	memcpy(smac, dev_addr.src_dev_addr, ETH_ALEN); +	return ret; +} +EXPORT_SYMBOL(rdma_addr_find_smac_by_sgid); +  static int netevent_callback(struct notifier_block *self, unsigned long event,  	void *ctx)  { @@ -461,11 +550,13 @@ static int __init addr_init(void)  		return -ENOMEM;  	register_netevent_notifier(&nb); +	rdma_addr_register_client(&self);  	return 0;  }  static void __exit addr_cleanup(void)  { +	rdma_addr_unregister_client(&self);  	unregister_netevent_notifier(&nb);  	destroy_workqueue(addr_wq);  }  | 
