svn commit: r213941 - projects/ofed/head/sys/ofed/drivers/infiniband/core

Jeff Roberson jeff at FreeBSD.org
Sun Oct 17 00:14:41 UTC 2010


Author: jeff
Date: Sun Oct 17 00:14:41 2010
New Revision: 213941
URL: http://svn.freebsd.org/changeset/base/213941

Log:
   - Implement the rdma address resolution function which converts an ip
     address into an ethernet mac or ib gid.  The resolution function
     accepts an optional source address to select the interface to
     route to.  We verify that this is a valid path for the destination
     and issue an arp request if the dest is not yet resolved.
  
  Sponsored by:	Isilon Systems, iX Systems, and Panasas.
  Reviewed by:	kmacy

Modified:
  projects/ofed/head/sys/ofed/drivers/infiniband/core/addr.c

Modified: projects/ofed/head/sys/ofed/drivers/infiniband/core/addr.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/infiniband/core/addr.c	Sun Oct 17 00:12:11 2010	(r213940)
+++ projects/ofed/head/sys/ofed/drivers/infiniband/core/addr.c	Sun Oct 17 00:14:41 2010	(r213941)
@@ -105,11 +105,11 @@ int rdma_copy_addr(struct rdma_dev_addr 
 		     const unsigned char *dst_dev_addr)
 {
 	dev_addr->dev_type = dev->if_type;
-	memcpy(dev_addr->src_dev_addr, IF_LLADDR(dev), MAX_ADDR_LEN);
+	memcpy(dev_addr->src_dev_addr, IF_LLADDR(dev), dev->if_addrlen);
 	memcpy(dev_addr->broadcast, __DECONST(char *, dev->if_broadcastaddr),
-	    MAX_ADDR_LEN);
+	    dev->if_addrlen);
 	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, dev->if_addrlen);
 	dev_addr->bound_dev_if = dev->if_index;
 	return 0;
 }
@@ -132,7 +132,7 @@ int rdma_translate_ip(struct sockaddr *a
 
 	switch (addr->sa_family) {
 	case AF_INET:
-		dev = ip_dev_find(&init_net,
+		dev = ip_dev_find(NULL,
 			((struct sockaddr_in *) addr)->sin_addr.s_addr);
 
 		if (!dev)
@@ -142,7 +142,7 @@ int rdma_translate_ip(struct sockaddr *a
 		dev_put(dev);
 		break;
 
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if defined(INET6)
 	case AF_INET6:
 		read_lock(&dev_base_lock);
 		for_each_netdev(&init_net, dev) {
@@ -246,7 +246,7 @@ out:
 	return ret;
 }
 
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if defined(INET6)
 static int addr6_resolve(struct sockaddr_in6 *src_in,
 			 struct sockaddr_in6 *dst_in,
 			 struct rdma_dev_addr *addr)
@@ -310,32 +310,119 @@ static int addr6_resolve(struct sockaddr
 #endif
 
 #else
-
-static int addr6_resolve(struct sockaddr_in6 *src_in,
-			 struct sockaddr_in6 *dst_in,
-			 struct rdma_dev_addr *addr)
-{
-	return -EADDRNOTAVAIL;
-}
-
-static int addr4_resolve(struct sockaddr_in *src_in,
-			 struct sockaddr_in *dst_in,
-			 struct rdma_dev_addr *addr)
-{
-	/* XXX This will have to be filled in after ipoib is functional. */
-	return -EADDRNOTAVAIL;
-}
+#include <netinet/if_ether.h>
+#ifdef INET6
+#include <netinet6/nd6.h>
+#endif
 
 static int addr_resolve(struct sockaddr *src_in,
 			struct sockaddr *dst_in,
 			struct rdma_dev_addr *addr)
 {
-	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 ifaddr *ifa;
+	struct ifnet *ifp;
+	struct llentry *lle;
+	struct rtentry *rte;
+	u_char edst[MAX_ADDR_LEN];
+	int multi;
+	int bcast;
+	int error;
+
+	/*
+	 * Determine whether the address is unicast, multicast, or broadcast
+	 * and whether the source interface is valid.
+	 */
+	multi = 0;
+	bcast = 0;
+	ifp = NULL;
+	switch (dst_in->sa_family) {
+	case AF_INET:
+		if (((struct sockaddr_in *)dst_in)->sin_addr.s_addr ==
+		    INADDR_BROADCAST)
+			bcast = 1;
+		if (IN_MULTICAST((
+		    (struct sockaddr_in *)dst_in)->sin_addr.s_addr))
+			multi = 1;
+		if (((struct sockaddr_in *)src_in)->sin_addr.s_addr ==
+		    INADDR_ANY)
+			src_in = NULL; 
+		break;
+#ifdef INET6
+	case AF_INET6:
+		if (IN6_IS_ADDR_MULTICAST(
+		    &((struct sockaddr_in6 *)dst_in)->sin6_addr))
+			multi = 1;
+		if (IN6_IS_ADDR_UNSPECIFIED(
+		    &((struct sockaddr_in6 *)src_in)->sin6_addr))
+			src_in = NULL;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+	/*
+	 * If we have a source address to use look it up first and verify
+	 * that it is a local interface.
+	 */
+	if (src_in) {
+		ifa = ifa_ifwithdstaddr(src_in);
+		if (ifa == NULL)
+			return -ENETUNREACH;
+		ifp = ifa->ifa_ifp;
+		ifa_free(ifa);
+		if (bcast || multi)
+			goto mcast;
+	}
+	/*
+	 * Make sure the route exists and has a valid link.
+	 */
+	rte = rtalloc1(dst_in, 1, 0);
+	if (rte == NULL || rte->rt_ifp == NULL || !RT_LINK_IS_UP(rte->rt_ifp)) {
+		if (rte)
+			RTFREE(rte);
+		return -EHOSTUNREACH;
+	}
+	/*
+	 * If it's not multicast or broadcast and the route doesn't match the
+	 * requested interface return unreachable.
+	 */
+	if (multi || bcast) {
+		RTFREE(rte);
+	} else if (ifp && ifp != rte->rt_ifp) {
+		RTFREE(rte);
+		return -ENETUNREACH;
+	}
+	if (ifp == NULL)
+		ifp = rte->rt_ifp;
+mcast:
+	if (bcast)
+		return rdma_copy_addr(addr, ifp, ifp->if_broadcastaddr);
+	if (multi) {
+		struct sockaddr *llsa;
+
+		error = ifp->if_resolvemulti(ifp, &llsa, dst_in);
+		if (error)
+			return -error;
+		error = rdma_copy_addr(addr, ifp,
+		    LLADDR((struct sockaddr_dl *)llsa));
+		free(llsa, M_IFMADDR);
+		return error;
+	}
+	/*
+	 * Resolve the link local address.
+	 */
+	if (dst_in->sa_family == AF_INET)
+		error = arpresolve(ifp, rte, NULL, dst_in, edst, &lle);
+#ifdef INET6
+	else
+		error = nd6_storelladdr(ifp, NULL, dst_in, (u_char *)edst, &lle);
+#endif
+	RTFREE(rte);
+	if (error == 0)
+		return rdma_copy_addr(addr, ifp, edst);
+	if (error == EWOULDBLOCK)
+		return -ENODATA;
+	return -error;
 }
 
 #endif


More information about the svn-src-projects mailing list