|
@@ -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);
|
|
|
}
|