[openib-general] [PATCH 1/3] RDMA CM: fix resolve_addr() failing if bind_addr() does not bind to a device

Sean Hefty sean.hefty at intel.com
Thu Mar 30 18:00:00 PST 2006


If the user calls rdma_bind_addr(), but specifies either a zero IP address, 
or the loopback address, bind will succeed, but the cm_id will not attach
to an RDMA device.  This will result in a failure if rdma_resolve_addr()
is called.  Fix rdma_resolve_addr(), so that it handles this condition
properly.

To correct this, rdma_resolve_addr() calls rdma_bind_addr() if it has not
already been called by the user.  A minor correction to rdma_bind_addr()
was made to better handle binding to a zero or loopback IP address.

Signed-off-by: Sean Hefty <sean.hefty at intel.com>

---

This fix should make it easier to assign port numbers to cm_id's, since
rdma_bind_addr() will be called for all cm_id's.



Index: cma.c
===================================================================
--- cma.c	(revision 6063)
+++ cma.c	(working copy)
@@ -443,14 +443,13 @@ int rdma_init_qp_attr(struct rdma_cm_id 
 }
 EXPORT_SYMBOL(rdma_init_qp_attr);
 
-static inline int cma_any_addr(struct sockaddr *addr)
+static inline int cma_zero_addr(struct sockaddr *addr)
 {
 	struct in6_addr *ip6;
 
-	if (addr->sa_family == AF_INET) {
-		__u32 s_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
-		return ZERONET(s_addr) || LOOPBACK(s_addr);
-	} else {
+	if (addr->sa_family == AF_INET)
+		return ZERONET(((struct sockaddr_in *) addr)->sin_addr.s_addr);
+	else {
 		ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
 		return (ip6->s6_addr32[0] | ip6->s6_addr32[1] |
 			ip6->s6_addr32[3] | ip6->s6_addr32[4]) == 0;
@@ -462,6 +461,11 @@ static inline int cma_loopback_addr(stru
 	return LOOPBACK(((struct sockaddr_in *) addr)->sin_addr.s_addr);
 }
 
+static inline int cma_any_addr(struct sockaddr *addr)
+{
+	return cma_zero_addr(addr) || cma_loopback_addr(addr);
+}
+
 static int cma_get_net_info(void *hdr, enum rdma_port_space ps,
 			    u8 *ip_ver, __u16 *port,
 			    union cma_ip_addr **src, union cma_ip_addr **dst)
@@ -1212,18 +1216,13 @@ static void addr_handler(int status, str
 {
 	struct rdma_id_private *id_priv = context;
 	enum rdma_cm_event_type event;
-	enum cma_state old_state;
 
 	atomic_inc(&id_priv->dev_remove);
-	if (!id_priv->cma_dev) {
-		old_state = CMA_IDLE;
-		if (!status)
-			status = cma_acquire_dev(id_priv);
-	} else
-		old_state = CMA_ADDR_BOUND;
+	if (!id_priv->cma_dev && !status)
+		status = cma_acquire_dev(id_priv);
 
 	if (status) {
-		if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, old_state))
+		if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND))
 			goto out;
 		event = RDMA_CM_EVENT_ADDR_ERROR;
 	} else {
@@ -1246,27 +1245,30 @@ out:
 	cma_deref_id(id_priv);
 }
 
-static int cma_resolve_loopback(struct rdma_id_private *id_priv,
-				struct sockaddr *src_addr, enum cma_state state)
+static int cma_resolve_loopback(struct rdma_id_private *id_priv)
 {
 	struct cma_work *work;
-	struct rdma_dev_addr *dev_addr;
+	struct sockaddr_in *src_in, *dst_in;
 	int ret;
 
 	work = kzalloc(sizeof *work, GFP_KERNEL);
 	if (!work)
 		return -ENOMEM;
 
-	if (state == CMA_IDLE) {
+	if (!id_priv->cma_dev) {
 		ret = cma_bind_loopback(id_priv);
 		if (ret)
 			goto err;
-		dev_addr = &id_priv->id.route.addr.dev_addr;
-		ib_addr_set_dgid(dev_addr, ib_addr_get_sgid(dev_addr));
-		if (!src_addr || cma_any_addr(src_addr))
-			src_addr = &id_priv->id.route.addr.dst_addr;
-		memcpy(&id_priv->id.route.addr.src_addr, src_addr,
-		       ip_addr_size(src_addr));
+	}
+
+	ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr,
+			 ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr));
+
+	if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) {
+		src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr;
+		dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr;
+		src_in->sin_family = dst_in->sin_family;
+		src_in->sin_addr.s_addr = dst_in->sin_addr.s_addr;
 	}
 
 	work->id = id_priv;
@@ -1281,29 +1283,42 @@ err:
 	return ret;
 }
 
+static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
+			 struct sockaddr *dst_addr)
+{
+	struct sockaddr_in addr_in;
+
+	if (src_addr && src_addr->sa_family)
+		return rdma_bind_addr(id, src_addr);
+	else {
+		memset(&addr_in, 0, sizeof addr_in);
+		addr_in.sin_family = dst_addr->sa_family;
+		return rdma_bind_addr(id, (struct sockaddr *) &addr_in);
+	}
+}
+
 int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
 		      struct sockaddr *dst_addr, int timeout_ms)
 {
 	struct rdma_id_private *id_priv;
-	enum cma_state expected_state;
 	int ret;
 
 	id_priv = container_of(id, struct rdma_id_private, id);
-	if (id_priv->cma_dev) {
-		expected_state = CMA_ADDR_BOUND;
-		src_addr = &id->route.addr.src_addr;
-	} else
-		expected_state = CMA_IDLE;
+	if (id_priv->state == CMA_IDLE) {
+		ret = cma_bind_addr(id, src_addr, dst_addr);
+		if (ret)
+			return ret;
+	}
 
-	if (!cma_comp_exch(id_priv, expected_state, CMA_ADDR_QUERY))
+	if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY))
 		return -EINVAL;
 
 	atomic_inc(&id_priv->refcount);
 	memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr));
 	if (cma_loopback_addr(dst_addr))
-		ret = cma_resolve_loopback(id_priv, src_addr, expected_state);
+		ret = cma_resolve_loopback(id_priv);
 	else
-		ret = rdma_resolve_ip(src_addr, dst_addr,
+		ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr,
 				      &id->route.addr.dev_addr,
 				      timeout_ms, addr_handler, id_priv);
 	if (ret)
@@ -1311,7 +1326,7 @@ int rdma_resolve_addr(struct rdma_cm_id 
 
 	return 0;
 err:
-	cma_comp_exch(id_priv, CMA_ADDR_QUERY, expected_state);
+	cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND);
 	cma_deref_id(id_priv);
 	return ret;
 }
@@ -1330,11 +1345,9 @@ int rdma_bind_addr(struct rdma_cm_id *id
 	if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND))
 		return -EINVAL;
 
-	if (cma_any_addr(addr)) {
+	if (cma_any_addr(addr))
 		ret = 0;
-	} else if (cma_loopback_addr(addr)) {
-		ret = cma_bind_loopback(id_priv);
-	} else {
+	else {
 		dev_addr = &id->route.addr.dev_addr;
 		ret = rdma_translate_ip(addr, dev_addr);
 		if (!ret)




More information about the general mailing list