|
@@ -121,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(const struct sockaddr *addr,
|
|
|
+ struct rdma_dev_addr *dev_addr,
|
|
|
u16 *vlan_id)
|
|
|
{
|
|
|
struct net_device *dev;
|
|
@@ -139,7 +140,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr,
|
|
|
switch (addr->sa_family) {
|
|
|
case AF_INET:
|
|
|
dev = ip_dev_find(dev_addr->net,
|
|
|
- ((struct sockaddr_in *) addr)->sin_addr.s_addr);
|
|
|
+ ((const struct sockaddr_in *)addr)->sin_addr.s_addr);
|
|
|
|
|
|
if (!dev)
|
|
|
return ret;
|
|
@@ -154,7 +155,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr,
|
|
|
rcu_read_lock();
|
|
|
for_each_netdev_rcu(dev_addr->net, dev) {
|
|
|
if (ipv6_chk_addr(dev_addr->net,
|
|
|
- &((struct sockaddr_in6 *) addr)->sin6_addr,
|
|
|
+ &((const struct sockaddr_in6 *)addr)->sin6_addr,
|
|
|
dev, 1)) {
|
|
|
ret = rdma_copy_addr(dev_addr, dev, NULL);
|
|
|
if (vlan_id)
|
|
@@ -198,7 +199,8 @@ static void queue_req(struct addr_req *req)
|
|
|
mutex_unlock(&lock);
|
|
|
}
|
|
|
|
|
|
-static int dst_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr, void *daddr)
|
|
|
+static int dst_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr,
|
|
|
+ const void *daddr)
|
|
|
{
|
|
|
struct neighbour *n;
|
|
|
int ret;
|
|
@@ -222,8 +224,9 @@ static int dst_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr, v
|
|
|
}
|
|
|
|
|
|
static int addr4_resolve(struct sockaddr_in *src_in,
|
|
|
- struct sockaddr_in *dst_in,
|
|
|
- struct rdma_dev_addr *addr)
|
|
|
+ const struct sockaddr_in *dst_in,
|
|
|
+ struct rdma_dev_addr *addr,
|
|
|
+ struct rtable **prt)
|
|
|
{
|
|
|
__be32 src_ip = src_in->sin_addr.s_addr;
|
|
|
__be32 dst_ip = dst_in->sin_addr.s_addr;
|
|
@@ -243,36 +246,23 @@ static int addr4_resolve(struct sockaddr_in *src_in,
|
|
|
src_in->sin_family = AF_INET;
|
|
|
src_in->sin_addr.s_addr = fl4.saddr;
|
|
|
|
|
|
- if (rt->dst.dev->flags & IFF_LOOPBACK) {
|
|
|
- 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;
|
|
|
- }
|
|
|
-
|
|
|
- /* If the device does ARP internally, return 'done' */
|
|
|
- if (rt->dst.dev->flags & IFF_NOARP) {
|
|
|
- ret = rdma_copy_addr(addr, rt->dst.dev, NULL);
|
|
|
- goto put;
|
|
|
- }
|
|
|
-
|
|
|
/* If there's a gateway, we're definitely in RoCE v2 (as RoCE v1 isn't
|
|
|
* routable) and we could set the network type accordingly.
|
|
|
*/
|
|
|
if (rt->rt_uses_gateway)
|
|
|
addr->network = RDMA_NETWORK_IPV4;
|
|
|
|
|
|
- ret = dst_fetch_ha(&rt->dst, addr, &fl4.daddr);
|
|
|
-put:
|
|
|
- ip_rt_put(rt);
|
|
|
+ *prt = rt;
|
|
|
+ return 0;
|
|
|
out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
|
static int addr6_resolve(struct sockaddr_in6 *src_in,
|
|
|
- struct sockaddr_in6 *dst_in,
|
|
|
- struct rdma_dev_addr *addr)
|
|
|
+ const struct sockaddr_in6 *dst_in,
|
|
|
+ struct rdma_dev_addr *addr,
|
|
|
+ struct dst_entry **pdst)
|
|
|
{
|
|
|
struct flowi6 fl6;
|
|
|
struct dst_entry *dst;
|
|
@@ -299,49 +289,109 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
|
|
|
src_in->sin6_addr = fl6.saddr;
|
|
|
}
|
|
|
|
|
|
- if (dst->dev->flags & IFF_LOOPBACK) {
|
|
|
- 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;
|
|
|
- }
|
|
|
-
|
|
|
- /* If the device does ARP internally, return 'done' */
|
|
|
- if (dst->dev->flags & IFF_NOARP) {
|
|
|
- ret = rdma_copy_addr(addr, dst->dev, NULL);
|
|
|
- goto put;
|
|
|
- }
|
|
|
-
|
|
|
/* If there's a gateway, we're definitely in RoCE v2 (as RoCE v1 isn't
|
|
|
* routable) and we could set the network type accordingly.
|
|
|
*/
|
|
|
if (rt->rt6i_flags & RTF_GATEWAY)
|
|
|
addr->network = RDMA_NETWORK_IPV6;
|
|
|
|
|
|
- ret = dst_fetch_ha(dst, addr, &fl6.daddr);
|
|
|
+ *pdst = dst;
|
|
|
+ return 0;
|
|
|
put:
|
|
|
dst_release(dst);
|
|
|
return ret;
|
|
|
}
|
|
|
#else
|
|
|
static int addr6_resolve(struct sockaddr_in6 *src_in,
|
|
|
- struct sockaddr_in6 *dst_in,
|
|
|
- struct rdma_dev_addr *addr)
|
|
|
+ const struct sockaddr_in6 *dst_in,
|
|
|
+ struct rdma_dev_addr *addr,
|
|
|
+ struct dst_entry **pdst)
|
|
|
{
|
|
|
return -EADDRNOTAVAIL;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+static int addr_resolve_neigh(struct dst_entry *dst,
|
|
|
+ const struct sockaddr *dst_in,
|
|
|
+ struct rdma_dev_addr *addr)
|
|
|
+{
|
|
|
+ if (dst->dev->flags & IFF_LOOPBACK) {
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = rdma_translate_ip(dst_in, addr, NULL);
|
|
|
+ if (!ret)
|
|
|
+ memcpy(addr->dst_dev_addr, addr->src_dev_addr,
|
|
|
+ MAX_ADDR_LEN);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If the device doesn't do ARP internally */
|
|
|
+ if (!(dst->dev->flags & IFF_NOARP)) {
|
|
|
+ const struct sockaddr_in *dst_in4 =
|
|
|
+ (const struct sockaddr_in *)dst_in;
|
|
|
+ const struct sockaddr_in6 *dst_in6 =
|
|
|
+ (const struct sockaddr_in6 *)dst_in;
|
|
|
+
|
|
|
+ return dst_fetch_ha(dst, addr,
|
|
|
+ dst_in->sa_family == AF_INET ?
|
|
|
+ (const void *)&dst_in4->sin_addr.s_addr :
|
|
|
+ (const void *)&dst_in6->sin6_addr);
|
|
|
+ }
|
|
|
+
|
|
|
+ return rdma_copy_addr(addr, dst->dev, NULL);
|
|
|
+}
|
|
|
+
|
|
|
static int addr_resolve(struct sockaddr *src_in,
|
|
|
- struct sockaddr *dst_in,
|
|
|
- struct rdma_dev_addr *addr)
|
|
|
+ const struct sockaddr *dst_in,
|
|
|
+ struct rdma_dev_addr *addr,
|
|
|
+ bool resolve_neigh)
|
|
|
{
|
|
|
+ struct net_device *ndev;
|
|
|
+ struct dst_entry *dst;
|
|
|
+ int ret;
|
|
|
+
|
|
|
if (src_in->sa_family == AF_INET) {
|
|
|
- return addr4_resolve((struct sockaddr_in *) src_in,
|
|
|
- (struct sockaddr_in *) dst_in, addr);
|
|
|
- } else
|
|
|
- return addr6_resolve((struct sockaddr_in6 *) src_in,
|
|
|
- (struct sockaddr_in6 *) dst_in, addr);
|
|
|
+ struct rtable *rt = NULL;
|
|
|
+ const struct sockaddr_in *dst_in4 =
|
|
|
+ (const struct sockaddr_in *)dst_in;
|
|
|
+
|
|
|
+ ret = addr4_resolve((struct sockaddr_in *)src_in,
|
|
|
+ dst_in4, addr, &rt);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if (resolve_neigh)
|
|
|
+ ret = addr_resolve_neigh(&rt->dst, dst_in, addr);
|
|
|
+
|
|
|
+ ndev = rt->dst.dev;
|
|
|
+ dev_hold(ndev);
|
|
|
+
|
|
|
+ ip_rt_put(rt);
|
|
|
+ } else {
|
|
|
+ const struct sockaddr_in6 *dst_in6 =
|
|
|
+ (const struct sockaddr_in6 *)dst_in;
|
|
|
+
|
|
|
+ ret = addr6_resolve((struct sockaddr_in6 *)src_in,
|
|
|
+ dst_in6, addr,
|
|
|
+ &dst);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if (resolve_neigh)
|
|
|
+ ret = addr_resolve_neigh(dst, dst_in, addr);
|
|
|
+
|
|
|
+ ndev = dst->dev;
|
|
|
+ dev_hold(ndev);
|
|
|
+
|
|
|
+ dst_release(dst);
|
|
|
+ }
|
|
|
+
|
|
|
+ addr->bound_dev_if = ndev->ifindex;
|
|
|
+ addr->net = dev_net(ndev);
|
|
|
+ dev_put(ndev);
|
|
|
+
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static void process_req(struct work_struct *work)
|
|
@@ -357,7 +407,8 @@ static void process_req(struct work_struct *work)
|
|
|
if (req->status == -ENODATA) {
|
|
|
src_in = (struct sockaddr *) &req->src_addr;
|
|
|
dst_in = (struct sockaddr *) &req->dst_addr;
|
|
|
- req->status = addr_resolve(src_in, dst_in, req->addr);
|
|
|
+ req->status = addr_resolve(src_in, dst_in, req->addr,
|
|
|
+ true);
|
|
|
if (req->status && time_after_eq(jiffies, req->timeout))
|
|
|
req->status = -ETIMEDOUT;
|
|
|
else if (req->status == -ENODATA)
|
|
@@ -417,7 +468,7 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
|
|
|
req->client = client;
|
|
|
atomic_inc(&client->refcount);
|
|
|
|
|
|
- req->status = addr_resolve(src_in, dst_in, addr);
|
|
|
+ req->status = addr_resolve(src_in, dst_in, addr, true);
|
|
|
switch (req->status) {
|
|
|
case 0:
|
|
|
req->timeout = jiffies;
|
|
@@ -439,6 +490,25 @@ err:
|
|
|
}
|
|
|
EXPORT_SYMBOL(rdma_resolve_ip);
|
|
|
|
|
|
+int rdma_resolve_ip_route(struct sockaddr *src_addr,
|
|
|
+ const struct sockaddr *dst_addr,
|
|
|
+ struct rdma_dev_addr *addr)
|
|
|
+{
|
|
|
+ struct sockaddr_storage ssrc_addr = {};
|
|
|
+ struct sockaddr *src_in = (struct sockaddr *)&ssrc_addr;
|
|
|
+
|
|
|
+ if (src_addr->sa_family != dst_addr->sa_family)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (src_addr)
|
|
|
+ memcpy(src_in, src_addr, rdma_addr_size(src_addr));
|
|
|
+ else
|
|
|
+ src_in->sa_family = dst_addr->sa_family;
|
|
|
+
|
|
|
+ return addr_resolve(src_in, dst_addr, addr, false);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(rdma_resolve_ip_route);
|
|
|
+
|
|
|
void rdma_addr_cancel(struct rdma_dev_addr *addr)
|
|
|
{
|
|
|
struct addr_req *req, *temp_req;
|
|
@@ -471,7 +541,7 @@ static void resolve_cb(int status, struct sockaddr *src_addr,
|
|
|
}
|
|
|
|
|
|
int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgid,
|
|
|
- u8 *dmac, u16 *vlan_id, int if_index)
|
|
|
+ u8 *dmac, u16 *vlan_id, int *if_index)
|
|
|
{
|
|
|
int ret = 0;
|
|
|
struct rdma_dev_addr dev_addr;
|
|
@@ -489,7 +559,8 @@ int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgi
|
|
|
rdma_gid2ip(&dgid_addr._sockaddr, dgid);
|
|
|
|
|
|
memset(&dev_addr, 0, sizeof(dev_addr));
|
|
|
- dev_addr.bound_dev_if = if_index;
|
|
|
+ if (if_index)
|
|
|
+ dev_addr.bound_dev_if = *if_index;
|
|
|
dev_addr.net = &init_net;
|
|
|
|
|
|
ctx.addr = &dev_addr;
|
|
@@ -505,6 +576,8 @@ int rdma_addr_find_dmac_by_grh(const union ib_gid *sgid, const union ib_gid *dgi
|
|
|
dev = dev_get_by_index(&init_net, dev_addr.bound_dev_if);
|
|
|
if (!dev)
|
|
|
return -ENODEV;
|
|
|
+ if (if_index)
|
|
|
+ *if_index = dev_addr.bound_dev_if;
|
|
|
if (vlan_id)
|
|
|
*vlan_id = rdma_vlan_dev_vlan_id(dev);
|
|
|
dev_put(dev);
|