Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e69381b4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband: (45 commits)
  RDMA/cxgb3: Fix error paths in post_send and post_recv
  RDMA/nes: Fix stale ARP issue
  RDMA/nes: FIN during MPA startup causes timeout
  RDMA/nes: Free kmap() resources
  RDMA/nes: Check for zero STag
  RDMA/nes: Fix Xansation test crash on cm_node ref_count
  RDMA/nes: Abnormal listener exit causes loopback node crash
  RDMA/nes: Fix crash in nes_accept()
  RDMA/nes: Resource not freed for REJECTed connections
  RDMA/nes: MPA request/response error checking
  RDMA/nes: Fix query of ORD values
  RDMA/nes: Fix MAX_CM_BUFFER define
  RDMA/nes: Pass correct size to ioremap_nocache()
  RDMA/nes: Update copyright and branding string
  RDMA/nes: Add max_cqe check to nes_create_cq()
  RDMA/nes: Clean up struct nes_qp
  RDMA/nes: Implement IB_SIGNAL_ALL_WR as an iWARP extension
  RDMA/nes: Add additional SFP+ PHY uC status check and PHY reset
  RDMA/nes: Correct fast memory registration implementation
  IB/ehca: Fix error paths in post_send and post_recv
  ...
parents 238ccbb0 14f369d1
Loading
Loading
Loading
Loading
+5 −5
Original line number Original line Diff line number Diff line
@@ -36,11 +36,11 @@ Datagram vs Connected modes
  fabric with a 2K MTU, the IPoIB MTU will be 2048 - 4 = 2044 bytes.
  fabric with a 2K MTU, the IPoIB MTU will be 2048 - 4 = 2044 bytes.


  In connected mode, the IB RC (Reliable Connected) transport is used.
  In connected mode, the IB RC (Reliable Connected) transport is used.
  Connected mode is to takes advantage of the connected nature of the
  Connected mode takes advantage of the connected nature of the IB
  IB transport and allows an MTU up to the maximal IP packet size of
  transport and allows an MTU up to the maximal IP packet size of 64K,
  64K, which reduces the number of IP packets needed for handling
  which reduces the number of IP packets needed for handling large UDP
  large UDP datagrams, TCP segments, etc and increases the performance
  datagrams, TCP segments, etc and increases the performance for large
  for large messages.
  messages.


  In connected mode, the interface's UD QP is still used for multicast
  In connected mode, the interface's UD QP is still used for multicast
  and communication with peers that don't support connected mode. In
  and communication with peers that don't support connected mode. In
+98 −177
Original line number Original line Diff line number Diff line
@@ -36,7 +36,6 @@
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/inetdevice.h>
#include <linux/inetdevice.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/if_arp.h>
#include <net/arp.h>
#include <net/arp.h>
#include <net/neighbour.h>
#include <net/neighbour.h>
#include <net/route.h>
#include <net/route.h>
@@ -92,22 +91,12 @@ EXPORT_SYMBOL(rdma_addr_unregister_client);
int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
		     const unsigned char *dst_dev_addr)
		     const unsigned char *dst_dev_addr)
{
{
	switch (dev->type) {
	dev_addr->dev_type = dev->type;
	case ARPHRD_INFINIBAND:
		dev_addr->dev_type = RDMA_NODE_IB_CA;
		break;
	case ARPHRD_ETHER:
		dev_addr->dev_type = RDMA_NODE_RNIC;
		break;
	default:
		return -EADDRNOTAVAIL;
	}

	memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
	memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
	memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN);
	memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN);
	if (dst_dev_addr)
	if (dst_dev_addr)
		memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN);
		memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN);
	dev_addr->src_dev = dev;
	dev_addr->bound_dev_if = dev->ifindex;
	return 0;
	return 0;
}
}
EXPORT_SYMBOL(rdma_copy_addr);
EXPORT_SYMBOL(rdma_copy_addr);
@@ -117,6 +106,15 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
	struct net_device *dev;
	struct net_device *dev;
	int ret = -EADDRNOTAVAIL;
	int ret = -EADDRNOTAVAIL;


	if (dev_addr->bound_dev_if) {
		dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
		if (!dev)
			return -ENODEV;
		ret = rdma_copy_addr(dev_addr, dev, NULL);
		dev_put(dev);
		return ret;
	}

	switch (addr->sa_family) {
	switch (addr->sa_family) {
	case AF_INET:
	case AF_INET:
		dev = ip_dev_find(&init_net,
		dev = ip_dev_find(&init_net,
@@ -131,6 +129,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)


#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	case AF_INET6:
	case AF_INET6:
		read_lock(&dev_base_lock);
		for_each_netdev(&init_net, dev) {
		for_each_netdev(&init_net, dev) {
			if (ipv6_chk_addr(&init_net,
			if (ipv6_chk_addr(&init_net,
					  &((struct sockaddr_in6 *) addr)->sin6_addr,
					  &((struct sockaddr_in6 *) addr)->sin6_addr,
@@ -139,6 +138,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
				break;
				break;
			}
			}
		}
		}
		read_unlock(&dev_base_lock);
		break;
		break;
#endif
#endif
	}
	}
@@ -176,46 +176,7 @@ static void queue_req(struct addr_req *req)
	mutex_unlock(&lock);
	mutex_unlock(&lock);
}
}


static void addr_send_arp(struct sockaddr *dst_in)
static int addr4_resolve(struct sockaddr_in *src_in,
{
	struct rtable *rt;
	struct flowi fl;

	memset(&fl, 0, sizeof fl);

	switch (dst_in->sa_family) {
	case AF_INET:
		fl.nl_u.ip4_u.daddr =
			((struct sockaddr_in *) dst_in)->sin_addr.s_addr;

		if (ip_route_output_key(&init_net, &rt, &fl))
			return;

		neigh_event_send(rt->u.dst.neighbour, NULL);
		ip_rt_put(rt);
		break;

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	case AF_INET6:
	{
		struct dst_entry *dst;

		fl.nl_u.ip6_u.daddr =
			((struct sockaddr_in6 *) dst_in)->sin6_addr;

		dst = ip6_route_output(&init_net, NULL, &fl);
		if (!dst)
			return;

		neigh_event_send(dst->neighbour, NULL);
		dst_release(dst);
		break;
	}
#endif
	}
}

static int addr4_resolve_remote(struct sockaddr_in *src_in,
			 struct sockaddr_in *dst_in,
			 struct sockaddr_in *dst_in,
			 struct rdma_dev_addr *addr)
			 struct rdma_dev_addr *addr)
{
{
@@ -229,10 +190,22 @@ static int addr4_resolve_remote(struct sockaddr_in *src_in,
	memset(&fl, 0, sizeof fl);
	memset(&fl, 0, sizeof fl);
	fl.nl_u.ip4_u.daddr = dst_ip;
	fl.nl_u.ip4_u.daddr = dst_ip;
	fl.nl_u.ip4_u.saddr = src_ip;
	fl.nl_u.ip4_u.saddr = src_ip;
	fl.oif = addr->bound_dev_if;

	ret = ip_route_output_key(&init_net, &rt, &fl);
	ret = ip_route_output_key(&init_net, &rt, &fl);
	if (ret)
	if (ret)
		goto out;
		goto out;


	src_in->sin_family = AF_INET;
	src_in->sin_addr.s_addr = rt->rt_src;

	if (rt->idev->dev->flags & IFF_LOOPBACK) {
		ret = rdma_translate_ip((struct sockaddr *) dst_in, addr);
		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 the device does ARP internally, return 'done' */
	if (rt->idev->dev->flags & IFF_NOARP) {
	if (rt->idev->dev->flags & IFF_NOARP) {
		rdma_copy_addr(addr, rt->idev->dev, NULL);
		rdma_copy_addr(addr, rt->idev->dev, NULL);
@@ -240,19 +213,12 @@ static int addr4_resolve_remote(struct sockaddr_in *src_in,
	}
	}


	neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev);
	neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev);
	if (!neigh) {
	if (!neigh || !(neigh->nud_state & NUD_VALID)) {
		ret = -ENODATA;
		neigh_event_send(rt->u.dst.neighbour, NULL);
		goto put;
	}

	if (!(neigh->nud_state & NUD_VALID)) {
		ret = -ENODATA;
		ret = -ENODATA;
		if (neigh)
			goto release;
			goto release;
	}
		goto put;

	if (!src_ip) {
		src_in->sin_family = dst_in->sin_family;
		src_in->sin_addr.s_addr = rt->rt_src;
	}
	}


	ret = rdma_copy_addr(addr, neigh->dev, neigh->ha);
	ret = rdma_copy_addr(addr, neigh->dev, neigh->ha);
@@ -265,36 +231,61 @@ out:
}
}


#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static int addr6_resolve_remote(struct sockaddr_in6 *src_in,
static int addr6_resolve(struct sockaddr_in6 *src_in,
			 struct sockaddr_in6 *dst_in,
			 struct sockaddr_in6 *dst_in,
			 struct rdma_dev_addr *addr)
			 struct rdma_dev_addr *addr)
{
{
	struct flowi fl;
	struct flowi fl;
	struct neighbour *neigh;
	struct neighbour *neigh;
	struct dst_entry *dst;
	struct dst_entry *dst;
	int ret = -ENODATA;
	int ret;


	memset(&fl, 0, sizeof fl);
	memset(&fl, 0, sizeof fl);
	fl.nl_u.ip6_u.daddr = dst_in->sin6_addr;
	ipv6_addr_copy(&fl.fl6_dst, &dst_in->sin6_addr);
	fl.nl_u.ip6_u.saddr = src_in->sin6_addr;
	ipv6_addr_copy(&fl.fl6_src, &src_in->sin6_addr);
	fl.oif = addr->bound_dev_if;


	dst = ip6_route_output(&init_net, NULL, &fl);
	dst = ip6_route_output(&init_net, NULL, &fl);
	if (!dst)
	if ((ret = dst->error))
		return ret;
		goto put;

	if (ipv6_addr_any(&fl.fl6_src)) {
		ret = ipv6_dev_get_saddr(&init_net, ip6_dst_idev(dst)->dev,
					 &fl.fl6_dst, 0, &fl.fl6_src);
		if (ret)
			goto put;


		src_in->sin6_family = AF_INET6;
		ipv6_addr_copy(&src_in->sin6_addr, &fl.fl6_src);
	}

	if (dst->dev->flags & IFF_LOOPBACK) {
		ret = rdma_translate_ip((struct sockaddr *) dst_in, addr);
		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) {
	if (dst->dev->flags & IFF_NOARP) {
		ret = rdma_copy_addr(addr, dst->dev, NULL);
		ret = rdma_copy_addr(addr, dst->dev, NULL);
	} else {
		goto put;
	}

	neigh = dst->neighbour;
	neigh = dst->neighbour;
		if (neigh && (neigh->nud_state & NUD_VALID))
	if (!neigh || !(neigh->nud_state & NUD_VALID)) {
			ret = rdma_copy_addr(addr, neigh->dev, neigh->ha);
		neigh_event_send(dst->neighbour, NULL);
		ret = -ENODATA;
		goto put;
	}
	}


	ret = rdma_copy_addr(addr, dst->dev, neigh->ha);
put:
	dst_release(dst);
	dst_release(dst);
	return ret;
	return ret;
}
}
#else
#else
static int addr6_resolve_remote(struct sockaddr_in6 *src_in,
static int addr6_resolve(struct sockaddr_in6 *src_in,
			 struct sockaddr_in6 *dst_in,
			 struct sockaddr_in6 *dst_in,
			 struct rdma_dev_addr *addr)
			 struct rdma_dev_addr *addr)
{
{
@@ -302,15 +293,15 @@ static int addr6_resolve_remote(struct sockaddr_in6 *src_in,
}
}
#endif
#endif


static int addr_resolve_remote(struct sockaddr *src_in,
static int addr_resolve(struct sockaddr *src_in,
			struct sockaddr *dst_in,
			struct sockaddr *dst_in,
			struct rdma_dev_addr *addr)
			struct rdma_dev_addr *addr)
{
{
	if (src_in->sa_family == AF_INET) {
	if (src_in->sa_family == AF_INET) {
		return addr4_resolve_remote((struct sockaddr_in *) src_in,
		return addr4_resolve((struct sockaddr_in *) src_in,
			(struct sockaddr_in *) dst_in, addr);
			(struct sockaddr_in *) dst_in, addr);
	} else
	} else
		return addr6_resolve_remote((struct sockaddr_in6 *) src_in,
		return addr6_resolve((struct sockaddr_in6 *) src_in,
			(struct sockaddr_in6 *) dst_in, addr);
			(struct sockaddr_in6 *) dst_in, addr);
}
}


@@ -327,8 +318,7 @@ static void process_req(struct work_struct *work)
		if (req->status == -ENODATA) {
		if (req->status == -ENODATA) {
			src_in = (struct sockaddr *) &req->src_addr;
			src_in = (struct sockaddr *) &req->src_addr;
			dst_in = (struct sockaddr *) &req->dst_addr;
			dst_in = (struct sockaddr *) &req->dst_addr;
			req->status = addr_resolve_remote(src_in, dst_in,
			req->status = addr_resolve(src_in, dst_in, req->addr);
							  req->addr);
			if (req->status && time_after_eq(jiffies, req->timeout))
			if (req->status && time_after_eq(jiffies, req->timeout))
				req->status = -ETIMEDOUT;
				req->status = -ETIMEDOUT;
			else if (req->status == -ENODATA)
			else if (req->status == -ENODATA)
@@ -352,82 +342,6 @@ static void process_req(struct work_struct *work)
	}
	}
}
}


static int addr_resolve_local(struct sockaddr *src_in,
			      struct sockaddr *dst_in,
			      struct rdma_dev_addr *addr)
{
	struct net_device *dev;
	int ret;

	switch (dst_in->sa_family) {
	case AF_INET:
	{
		__be32 src_ip = ((struct sockaddr_in *) src_in)->sin_addr.s_addr;
		__be32 dst_ip = ((struct sockaddr_in *) dst_in)->sin_addr.s_addr;

		dev = ip_dev_find(&init_net, dst_ip);
		if (!dev)
			return -EADDRNOTAVAIL;

		if (ipv4_is_zeronet(src_ip)) {
			src_in->sa_family = dst_in->sa_family;
			((struct sockaddr_in *) src_in)->sin_addr.s_addr = dst_ip;
			ret = rdma_copy_addr(addr, dev, dev->dev_addr);
		} else if (ipv4_is_loopback(src_ip)) {
			ret = rdma_translate_ip(dst_in, addr);
			if (!ret)
				memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
		} else {
			ret = rdma_translate_ip(src_in, addr);
			if (!ret)
				memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
		}
		dev_put(dev);
		break;
	}

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	case AF_INET6:
	{
		struct in6_addr *a;

		for_each_netdev(&init_net, dev)
			if (ipv6_chk_addr(&init_net,
					  &((struct sockaddr_in6 *) dst_in)->sin6_addr,
					  dev, 1))
				break;

		if (!dev)
			return -EADDRNOTAVAIL;

		a = &((struct sockaddr_in6 *) src_in)->sin6_addr;

		if (ipv6_addr_any(a)) {
			src_in->sa_family = dst_in->sa_family;
			((struct sockaddr_in6 *) src_in)->sin6_addr =
				((struct sockaddr_in6 *) dst_in)->sin6_addr;
			ret = rdma_copy_addr(addr, dev, dev->dev_addr);
		} else if (ipv6_addr_loopback(a)) {
			ret = rdma_translate_ip(dst_in, addr);
			if (!ret)
				memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
		} else  {
			ret = rdma_translate_ip(src_in, addr);
			if (!ret)
				memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
		}
		break;
	}
#endif

	default:
		ret = -EADDRNOTAVAIL;
		break;
	}

	return ret;
}

int rdma_resolve_ip(struct rdma_addr_client *client,
int rdma_resolve_ip(struct rdma_addr_client *client,
		    struct sockaddr *src_addr, struct sockaddr *dst_addr,
		    struct sockaddr *src_addr, struct sockaddr *dst_addr,
		    struct rdma_dev_addr *addr, int timeout_ms,
		    struct rdma_dev_addr *addr, int timeout_ms,
@@ -443,22 +357,28 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
	if (!req)
	if (!req)
		return -ENOMEM;
		return -ENOMEM;


	if (src_addr)
	src_in = (struct sockaddr *) &req->src_addr;
		memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr));
	dst_in = (struct sockaddr *) &req->dst_addr;
	memcpy(&req->dst_addr, dst_addr, ip_addr_size(dst_addr));

	if (src_addr) {
		if (src_addr->sa_family != dst_addr->sa_family) {
			ret = -EINVAL;
			goto err;
		}

		memcpy(src_in, src_addr, ip_addr_size(src_addr));
	} else {
		src_in->sa_family = dst_addr->sa_family;
	}

	memcpy(dst_in, dst_addr, ip_addr_size(dst_addr));
	req->addr = addr;
	req->addr = addr;
	req->callback = callback;
	req->callback = callback;
	req->context = context;
	req->context = context;
	req->client = client;
	req->client = client;
	atomic_inc(&client->refcount);
	atomic_inc(&client->refcount);


	src_in = (struct sockaddr *) &req->src_addr;
	req->status = addr_resolve(src_in, dst_in, addr);
	dst_in = (struct sockaddr *) &req->dst_addr;

	req->status = addr_resolve_local(src_in, dst_in, addr);
	if (req->status == -EADDRNOTAVAIL)
		req->status = addr_resolve_remote(src_in, dst_in, addr);

	switch (req->status) {
	switch (req->status) {
	case 0:
	case 0:
		req->timeout = jiffies;
		req->timeout = jiffies;
@@ -467,15 +387,16 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
	case -ENODATA:
	case -ENODATA:
		req->timeout = msecs_to_jiffies(timeout_ms) + jiffies;
		req->timeout = msecs_to_jiffies(timeout_ms) + jiffies;
		queue_req(req);
		queue_req(req);
		addr_send_arp(dst_in);
		break;
		break;
	default:
	default:
		ret = req->status;
		ret = req->status;
		atomic_dec(&client->refcount);
		atomic_dec(&client->refcount);
		kfree(req);
		goto err;
		break;
	}
	}
	return ret;
	return ret;
err:
	kfree(req);
	return ret;
}
}
EXPORT_SYMBOL(rdma_resolve_ip);
EXPORT_SYMBOL(rdma_resolve_ip);


+83 −50
Original line number Original line Diff line number Diff line
@@ -330,17 +330,7 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv)
	union ib_gid gid;
	union ib_gid gid;
	int ret = -ENODEV;
	int ret = -ENODEV;


	switch (rdma_node_get_transport(dev_addr->dev_type)) {
	rdma_addr_get_sgid(dev_addr, &gid);
	case RDMA_TRANSPORT_IB:
		ib_addr_get_sgid(dev_addr, &gid);
		break;
	case RDMA_TRANSPORT_IWARP:
		iw_addr_get_sgid(dev_addr, &gid);
		break;
	default:
		return -ENODEV;
	}

	list_for_each_entry(cma_dev, &dev_list, list) {
	list_for_each_entry(cma_dev, &dev_list, list) {
		ret = ib_find_cached_gid(cma_dev->device, &gid,
		ret = ib_find_cached_gid(cma_dev->device, &gid,
					 &id_priv->id.port_num, NULL);
					 &id_priv->id.port_num, NULL);
@@ -1032,11 +1022,17 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
	if (rt->num_paths == 2)
	if (rt->num_paths == 2)
		rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
		rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;


	ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
	if (cma_any_addr((struct sockaddr *) &rt->addr.src_addr)) {
	ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr,
		rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND;
				&id->route.addr.dev_addr);
		rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
		ib_addr_set_pkey(&rt->addr.dev_addr, rt->path_rec[0].pkey);
	} else {
		ret = rdma_translate_ip((struct sockaddr *) &rt->addr.src_addr,
					&rt->addr.dev_addr);
		if (ret)
		if (ret)
			goto destroy_id;
			goto destroy_id;
	}
	rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);


	id_priv = container_of(id, struct rdma_id_private, id);
	id_priv = container_of(id, struct rdma_id_private, id);
	id_priv->state = CMA_CONNECT;
	id_priv->state = CMA_CONNECT;
@@ -1071,10 +1067,12 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
	cma_save_net_info(&id->route.addr, &listen_id->route.addr,
	cma_save_net_info(&id->route.addr, &listen_id->route.addr,
			  ip_ver, port, src, dst);
			  ip_ver, port, src, dst);


	if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) {
		ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr,
		ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr,
					&id->route.addr.dev_addr);
					&id->route.addr.dev_addr);
		if (ret)
		if (ret)
			goto err;
			goto err;
	}


	id_priv = container_of(id, struct rdma_id_private, id);
	id_priv = container_of(id, struct rdma_id_private, id);
	id_priv->state = CMA_CONNECT;
	id_priv->state = CMA_CONNECT;
@@ -1474,15 +1472,6 @@ static void cma_listen_on_all(struct rdma_id_private *id_priv)
	mutex_unlock(&lock);
	mutex_unlock(&lock);
}
}


static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af)
{
	struct sockaddr_storage addr_in;

	memset(&addr_in, 0, sizeof addr_in);
	addr_in.ss_family = af;
	return rdma_bind_addr(id, (struct sockaddr *) &addr_in);
}

int rdma_listen(struct rdma_cm_id *id, int backlog)
int rdma_listen(struct rdma_cm_id *id, int backlog)
{
{
	struct rdma_id_private *id_priv;
	struct rdma_id_private *id_priv;
@@ -1490,7 +1479,8 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)


	id_priv = container_of(id, struct rdma_id_private, id);
	id_priv = container_of(id, struct rdma_id_private, id);
	if (id_priv->state == CMA_IDLE) {
	if (id_priv->state == CMA_IDLE) {
		ret = cma_bind_any(id, AF_INET);
		((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
		ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
		if (ret)
		if (ret)
			return ret;
			return ret;
	}
	}
@@ -1565,8 +1555,8 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
	struct sockaddr_in6 *sin6;
	struct sockaddr_in6 *sin6;


	memset(&path_rec, 0, sizeof path_rec);
	memset(&path_rec, 0, sizeof path_rec);
	ib_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
	rdma_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
	ib_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
	rdma_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
	path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr));
	path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr));
	path_rec.numb_path = 1;
	path_rec.numb_path = 1;
	path_rec.reversible = 1;
	path_rec.reversible = 1;
@@ -1781,7 +1771,11 @@ port_found:
	if (ret)
	if (ret)
		goto out;
		goto out;


	ib_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
	id_priv->id.route.addr.dev_addr.dev_type =
		(rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB) ?
		ARPHRD_INFINIBAND : ARPHRD_ETHER;

	rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
	ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
	ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
	id_priv->id.port_num = p;
	id_priv->id.port_num = p;
	cma_attach_to_dev(id_priv, cma_dev);
	cma_attach_to_dev(id_priv, cma_dev);
@@ -1839,7 +1833,7 @@ out:
static int cma_resolve_loopback(struct rdma_id_private *id_priv)
static int cma_resolve_loopback(struct rdma_id_private *id_priv)
{
{
	struct cma_work *work;
	struct cma_work *work;
	struct sockaddr_in *src_in, *dst_in;
	struct sockaddr *src, *dst;
	union ib_gid gid;
	union ib_gid gid;
	int ret;
	int ret;


@@ -1853,14 +1847,19 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
			goto err;
			goto err;
	}
	}


	ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
	rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
	ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
	rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);


	if (cma_zero_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)) {
	src = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
		src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr;
	if (cma_zero_addr(src)) {
		dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr;
		dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
		src_in->sin_family = dst_in->sin_family;
		if ((src->sa_family = dst->sa_family) == AF_INET) {
		src_in->sin_addr.s_addr = dst_in->sin_addr.s_addr;
			((struct sockaddr_in *) src)->sin_addr.s_addr =
				((struct sockaddr_in *) dst)->sin_addr.s_addr;
		} else {
			ipv6_addr_copy(&((struct sockaddr_in6 *) src)->sin6_addr,
				       &((struct sockaddr_in6 *) dst)->sin6_addr);
		}
	}
	}


	work->id = id_priv;
	work->id = id_priv;
@@ -1878,10 +1877,14 @@ err:
static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
			 struct sockaddr *dst_addr)
			 struct sockaddr *dst_addr)
{
{
	if (src_addr && src_addr->sa_family)
	if (!src_addr || !src_addr->sa_family) {
		src_addr = (struct sockaddr *) &id->route.addr.src_addr;
		if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) {
			((struct sockaddr_in6 *) src_addr)->sin6_scope_id =
				((struct sockaddr_in6 *) dst_addr)->sin6_scope_id;
		}
	}
	return rdma_bind_addr(id, src_addr);
	return rdma_bind_addr(id, src_addr);
	else
		return cma_bind_any(id, dst_addr->sa_family);
}
}


int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
@@ -2077,6 +2080,25 @@ static int cma_get_port(struct rdma_id_private *id_priv)
	return ret;
	return ret;
}
}


static int cma_check_linklocal(struct rdma_dev_addr *dev_addr,
			       struct sockaddr *addr)
{
#if defined(CONFIG_IPv6) || defined(CONFIG_IPV6_MODULE)
	struct sockaddr_in6 *sin6;

	if (addr->sa_family != AF_INET6)
		return 0;

	sin6 = (struct sockaddr_in6 *) addr;
	if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
	    !sin6->sin6_scope_id)
			return -EINVAL;

	dev_addr->bound_dev_if = sin6->sin6_scope_id;
#endif
	return 0;
}

int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
{
{
	struct rdma_id_private *id_priv;
	struct rdma_id_private *id_priv;
@@ -2089,7 +2111,13 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
	if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND))
	if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND))
		return -EINVAL;
		return -EINVAL;


	if (!cma_any_addr(addr)) {
	ret = cma_check_linklocal(&id->route.addr.dev_addr, addr);
	if (ret)
		goto err1;

	if (cma_loopback_addr(addr)) {
		ret = cma_bind_loopback(id_priv);
	} else if (!cma_zero_addr(addr)) {
		ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
		ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
		if (ret)
		if (ret)
			goto err1;
			goto err1;
@@ -2108,7 +2136,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)


	return 0;
	return 0;
err2:
err2:
	if (!cma_any_addr(addr)) {
	if (id_priv->cma_dev) {
		mutex_lock(&lock);
		mutex_lock(&lock);
		cma_detach_from_dev(id_priv);
		cma_detach_from_dev(id_priv);
		mutex_unlock(&lock);
		mutex_unlock(&lock);
@@ -2687,10 +2715,15 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
	if (cma_any_addr(addr)) {
	if (cma_any_addr(addr)) {
		memset(mgid, 0, sizeof *mgid);
		memset(mgid, 0, sizeof *mgid);
	} else if ((addr->sa_family == AF_INET6) &&
	} else if ((addr->sa_family == AF_INET6) &&
		   ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFF10A01B) ==
		   ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) ==
								 0xFF10A01B)) {
								 0xFF10A01B)) {
		/* IPv6 address is an SA assigned MGID. */
		/* IPv6 address is an SA assigned MGID. */
		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
	} else if ((addr->sa_family == AF_INET6)) {
		ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map);
		if (id_priv->id.ps == RDMA_PS_UDP)
			mc_map[7] = 0x01;	/* Use RDMA CM signature */
		*mgid = *(union ib_gid *) (mc_map + 4);
	} else {
	} else {
		ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
		ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
		if (id_priv->id.ps == RDMA_PS_UDP)
		if (id_priv->id.ps == RDMA_PS_UDP)
@@ -2716,7 +2749,7 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
	cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid);
	cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid);
	if (id_priv->id.ps == RDMA_PS_UDP)
	if (id_priv->id.ps == RDMA_PS_UDP)
		rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
		rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
	ib_addr_get_sgid(dev_addr, &rec.port_gid);
	rdma_addr_get_sgid(dev_addr, &rec.port_gid);
	rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
	rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
	rec.join_state = 1;
	rec.join_state = 1;


@@ -2815,7 +2848,7 @@ static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id


	dev_addr = &id_priv->id.route.addr.dev_addr;
	dev_addr = &id_priv->id.route.addr.dev_addr;


	if ((dev_addr->src_dev == ndev) &&
	if ((dev_addr->bound_dev_if == ndev->ifindex) &&
	    memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) {
	    memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) {
		printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n",
		printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n",
		       ndev->name, &id_priv->id);
		       ndev->name, &id_priv->id);
+6 −0
Original line number Original line Diff line number Diff line
@@ -604,6 +604,12 @@ retry:
	return ret ? ret : id;
	return ret ? ret : id;
}
}


void ib_sa_unpack_path(void *attribute, struct ib_sa_path_rec *rec)
{
	ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table), attribute, rec);
}
EXPORT_SYMBOL(ib_sa_unpack_path);

static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
				    int status,
				    int status,
				    struct ib_sa_mad *mad)
				    struct ib_sa_mad *mad)
+53 −4
Original line number Original line Diff line number Diff line
@@ -43,6 +43,7 @@
#include <rdma/rdma_user_cm.h>
#include <rdma/rdma_user_cm.h>
#include <rdma/ib_marshall.h>
#include <rdma/ib_marshall.h>
#include <rdma/rdma_cm.h>
#include <rdma/rdma_cm.h>
#include <rdma/rdma_cm_ib.h>


MODULE_AUTHOR("Sean Hefty");
MODULE_AUTHOR("Sean Hefty");
MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
@@ -562,9 +563,9 @@ static void ucma_copy_ib_route(struct rdma_ucm_query_route_resp *resp,
	switch (route->num_paths) {
	switch (route->num_paths) {
	case 0:
	case 0:
		dev_addr = &route->addr.dev_addr;
		dev_addr = &route->addr.dev_addr;
		ib_addr_get_dgid(dev_addr,
		rdma_addr_get_dgid(dev_addr,
				   (union ib_gid *) &resp->ib_route[0].dgid);
				   (union ib_gid *) &resp->ib_route[0].dgid);
		ib_addr_get_sgid(dev_addr,
		rdma_addr_get_sgid(dev_addr,
				   (union ib_gid *) &resp->ib_route[0].sgid);
				   (union ib_gid *) &resp->ib_route[0].sgid);
		resp->ib_route[0].pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
		resp->ib_route[0].pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
		break;
		break;
@@ -812,6 +813,51 @@ static int ucma_set_option_id(struct ucma_context *ctx, int optname,
	return ret;
	return ret;
}
}


static int ucma_set_ib_path(struct ucma_context *ctx,
			    struct ib_path_rec_data *path_data, size_t optlen)
{
	struct ib_sa_path_rec sa_path;
	struct rdma_cm_event event;
	int ret;

	if (optlen % sizeof(*path_data))
		return -EINVAL;

	for (; optlen; optlen -= sizeof(*path_data), path_data++) {
		if (path_data->flags == (IB_PATH_GMP | IB_PATH_PRIMARY |
					 IB_PATH_BIDIRECTIONAL))
			break;
	}

	if (!optlen)
		return -EINVAL;

	ib_sa_unpack_path(path_data->path_rec, &sa_path);
	ret = rdma_set_ib_paths(ctx->cm_id, &sa_path, 1);
	if (ret)
		return ret;

	memset(&event, 0, sizeof event);
	event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
	return ucma_event_handler(ctx->cm_id, &event);
}

static int ucma_set_option_ib(struct ucma_context *ctx, int optname,
			      void *optval, size_t optlen)
{
	int ret;

	switch (optname) {
	case RDMA_OPTION_IB_PATH:
		ret = ucma_set_ib_path(ctx, optval, optlen);
		break;
	default:
		ret = -ENOSYS;
	}

	return ret;
}

static int ucma_set_option_level(struct ucma_context *ctx, int level,
static int ucma_set_option_level(struct ucma_context *ctx, int level,
				 int optname, void *optval, size_t optlen)
				 int optname, void *optval, size_t optlen)
{
{
@@ -821,6 +867,9 @@ static int ucma_set_option_level(struct ucma_context *ctx, int level,
	case RDMA_OPTION_ID:
	case RDMA_OPTION_ID:
		ret = ucma_set_option_id(ctx, optname, optval, optlen);
		ret = ucma_set_option_id(ctx, optname, optval, optlen);
		break;
		break;
	case RDMA_OPTION_IB:
		ret = ucma_set_option_ib(ctx, optname, optval, optlen);
		break;
	default:
	default:
		ret = -ENOSYS;
		ret = -ENOSYS;
	}
	}
Loading