From owner-svn-src-projects@FreeBSD.ORG Sun Oct 17 00:14:41 2010 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5DC641065670; Sun, 17 Oct 2010 00:14:41 +0000 (UTC) (envelope-from jeff@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 4BD908FC08; Sun, 17 Oct 2010 00:14:41 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o9H0EfvU096107; Sun, 17 Oct 2010 00:14:41 GMT (envelope-from jeff@svn.freebsd.org) Received: (from jeff@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o9H0Ef6w096105; Sun, 17 Oct 2010 00:14:41 GMT (envelope-from jeff@svn.freebsd.org) Message-Id: <201010170014.o9H0Ef6w096105@svn.freebsd.org> From: Jeff Roberson Date: Sun, 17 Oct 2010 00:14:41 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r213941 - projects/ofed/head/sys/ofed/drivers/infiniband/core X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 17 Oct 2010 00:14:41 -0000 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 +#ifdef INET6 +#include +#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