Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 16 Sep 2017 16:24:39 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r323646 - projects/bsd_rdma_4_9/sys/ofed/drivers/infiniband/core
Message-ID:  <201709161624.v8GGOdS8047118@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Sat Sep 16 16:24:38 2017
New Revision: 323646
URL: https://svnweb.freebsd.org/changeset/base/323646

Log:
  Improve ibcore address resolving:
  - Add more sanity checks.
  - Preserve source port number when resolving address.
  - Remove no longer needed scope ID hacks for IPv6.
  
  Sponsored by:	Mellanox Technologies

Modified:
  projects/bsd_rdma_4_9/sys/ofed/drivers/infiniband/core/ib_addr.c

Modified: projects/bsd_rdma_4_9/sys/ofed/drivers/infiniband/core/ib_addr.c
==============================================================================
--- projects/bsd_rdma_4_9/sys/ofed/drivers/infiniband/core/ib_addr.c	Sat Sep 16 16:23:00 2017	(r323645)
+++ projects/bsd_rdma_4_9/sys/ofed/drivers/infiniband/core/ib_addr.c	Sat Sep 16 16:24:38 2017	(r323646)
@@ -162,15 +162,10 @@ int rdma_translate_ip(const struct sockaddr *addr,
 		break;
 #endif
 #ifdef INET6
-	case AF_INET6: {
-		struct in6_addr in6_addr = ((const struct sockaddr_in6 *)addr)->sin6_addr;
-
-		/* embed scope ID */
-		in6_addr.s6_addr[3] = ((const struct sockaddr_in6 *)addr)->sin6_scope_id;
-
-		dev = ip6_dev_find(dev_addr->net, in6_addr);
+	case AF_INET6:
+		dev = ip6_dev_find(dev_addr->net,
+			((const struct sockaddr_in6 *)addr)->sin6_addr);
 		break;
-	}
 #endif
 	default:
 		break;
@@ -245,67 +240,90 @@ static int addr4_resolve(struct sockaddr_in *src_in,
 {
 	struct sockaddr_in dst_tmp = *dst_in;
 	u8 edst[MAX_ADDR_LEN];
+	in_port_t src_port;
+	struct sockaddr *saddr;
 	struct rtentry *rte;
 	struct ifnet *ifp;
 	int error;
+	int type;
 
-	/*
-	 * Make sure the socket address length field
-	 * is set, else rtalloc1() will fail.
-	 */
-	dst_tmp.sin_len = sizeof(dst_tmp);
-
+	/* set VNET, if any */
 	CURVNET_SET(addr->net);
+
 	/* set default TTL limit */
 	addr->hoplimit = V_ip_defttl;
 
-	/* lookup route for destination */
-	rte = rtalloc1((struct sockaddr *)&dst_tmp, 1, 0);
-	CURVNET_RESTORE();
+	type = 0;
+	if (src_in->sin_addr.s_addr == INADDR_ANY)
+		type |= 1;
+	if (dst_tmp.sin_addr.s_addr == INADDR_ANY)
+		type |= 2;
 
 	/*
-	 * Make sure the route exists and has a valid link.
+	 * Make sure the socket address length field
+	 * is set, else rtalloc1() will fail.
 	 */
-	if (rte == NULL) {
-		error = EHOSTUNREACH;
-		goto done;
-	} else if (rte->rt_ifp == NULL || RT_LINK_IS_UP(rte->rt_ifp) == 0) {
-		RTFREE_LOCKED(rte);
-		error = EHOSTUNREACH;
-		goto done;
-	} else if (src_in->sin_addr.s_addr != INADDR_ANY) {
+	dst_tmp.sin_len = sizeof(dst_tmp);
+
+	/* Step 1 - lookup destination route if any */
+	switch (type) {
+	case 0:
+	case 1:
+		/* regular destination route lookup */
+		rte = rtalloc1((struct sockaddr *)&dst_tmp, 1, 0);
+		if (rte == NULL) {
+			error = EHOSTUNREACH;
+			goto done;
+		} else if (rte->rt_ifp == NULL || rte->rt_ifp == V_loif ||
+		    RT_LINK_IS_UP(rte->rt_ifp) == 0) {
+			RTFREE_LOCKED(rte);
+			error = EHOSTUNREACH;
+			goto done;
+		}
 		RT_UNLOCK(rte);
+		break;
+	default:
+		error = ENETUNREACH;
+		goto done;
+	}
 
+	/* Step 2 - find outgoing network interface */
+	switch (type) {
+	case 0:
+		/* source check */
 		ifp = ip_dev_find(addr->net, src_in->sin_addr.s_addr);
 		if (ifp == NULL) {
-			RTFREE(rte);
 			error = ENETUNREACH;
-			goto done;
+			goto error_rt_free;
 		} else if (ifp != rte->rt_ifp) {
 			error = ENETUNREACH;
-			goto failure;
+			goto error_put_ifp;
 		}
-	} else {
-		struct sockaddr *saddr;
-
+		break;
+	case 1:
+		/* get destination network interface from route */
 		ifp = rte->rt_ifp;
 		dev_hold(ifp);
-
 		saddr = rte->rt_ifa->ifa_addr;
+
+		src_port = src_in->sin_port;
 		memcpy(src_in, saddr, rdma_addr_size(saddr));
-		RT_UNLOCK(rte);
+		src_in->sin_port = src_port;	/* preserve port number */
+		break;
+	default:
+		break;
 	}
 
 	/*
-	 * Resolve destination MAC address
+	 * Step 3 - resolve destination MAC address
 	 */
 	if (dst_tmp.sin_addr.s_addr == INADDR_BROADCAST) {
 		rdma_copy_addr_sub(edst, ifp->if_broadcastaddr,
-	            ifp->if_addrlen, MAX_ADDR_LEN);
+		    ifp->if_addrlen, MAX_ADDR_LEN);
 	} else if (IN_MULTICAST(ntohl(dst_tmp.sin_addr.s_addr))) {
 		error = addr_resolve_multi(edst, ifp, (struct sockaddr *)&dst_tmp);
 		if (error != 0)
-			goto failure;
+			goto error_put_ifp;
 	} else {
 		bool is_gw = (rte->rt_flags & RTF_GATEWAY) != 0;
 		memset(edst, 0, sizeof(edst));
@@ -313,26 +331,34 @@ static int addr4_resolve(struct sockaddr_in *src_in,
 		    rte->rt_gateway : (const struct sockaddr *)&dst_tmp,
 		    edst, NULL, NULL);
 		if (error != 0)
-			goto failure;
+			goto error_put_ifp;
 		else if (is_gw != 0)
 			addr->network = RDMA_NETWORK_IPV4;
 	}
 
 	/*
-	 * Copy destination and source MAC addresses
+	 * Step 4 - copy destination and source MAC addresses
 	 */
 	error = -rdma_copy_addr(addr, ifp, edst);
-	if (error != 0) {
-failure:
-		dev_put(ifp);
+	if (error != 0)
+		goto error_put_ifp;
 
-		if (error == EWOULDBLOCK || error == EAGAIN)
-			error = ENODATA;
-	} else {
-		*ifpp = ifp;
-	}
+	if (rte != NULL)
+		RTFREE(rte);
+
+	*ifpp = ifp;
+
+	goto done;
+
+error_put_ifp:
+	dev_put(ifp);
+error_rt_free:
 	RTFREE(rte);
 done:
+	CURVNET_RESTORE();
+
+	if (error == EWOULDBLOCK || error == EAGAIN)
+		error = ENODATA;
 	return (-error);
 }
 #else
@@ -353,67 +379,95 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
 {
 	struct sockaddr_in6 dst_tmp = *dst_in;
 	u8 edst[MAX_ADDR_LEN];
+	in_port_t src_port;
+	struct sockaddr *saddr;
 	struct rtentry *rte;
 	struct ifnet *ifp;
 	int error;
+	int type;
 
-	sa6_embedscope(&dst_tmp, 0);
-	sa6_embedscope(src_in, 0);
-
-	/*
-	 * Make sure the socket address length field
-	 * is set, else rtalloc1() will fail.
-	 */
-	dst_tmp.sin6_len = sizeof(dst_tmp);
-
+	/* set VNET, if any */
 	CURVNET_SET(addr->net);
+
 	/* set default TTL limit */
 	addr->hoplimit = V_ip_defttl;
 
-	/* lookup route for destination */
-	rte = rtalloc1((struct sockaddr *)&dst_tmp, 1, 0);
-	CURVNET_RESTORE();
+	type = 0;
+	if (ipv6_addr_any(&src_in->sin6_addr))
+		type |= 1;
+	if (ipv6_addr_any(&dst_tmp.sin6_addr))
+		type |= 2;
 
 	/*
-	 * Make sure the route exists and has a valid link.
+	 * Make sure the socket address length field
+	 * is set, else rtalloc1() will fail.
 	 */
-	if (rte == NULL) {
-		error = EHOSTUNREACH;
-		goto done;
-	} else if (rte->rt_ifp == NULL || RT_LINK_IS_UP(rte->rt_ifp) == 0) {
-		RTFREE_LOCKED(rte);
-		error = EHOSTUNREACH;
-		goto done;
-	} else if (!IN6_IS_ADDR_UNSPECIFIED(&src_in->sin6_addr)) {
+	dst_tmp.sin6_len = sizeof(dst_tmp);
+
+	/* Step 1 - lookup destination route if any */
+	switch (type) {
+	case 0:
+		/* sanity check for IPv4 addresses */
+		if (ipv6_addr_v4mapped(&src_in->sin6_addr) !=
+		    ipv6_addr_v4mapped(&dst_tmp.sin6_addr)) {
+			error = EAFNOSUPPORT;
+			goto done;
+		}
+		/* FALLTHROUGH */
+	case 1:
+		/* regular destination route lookup */
+		rte = rtalloc1((struct sockaddr *)&dst_tmp, 1, 0);
+		if (rte == NULL) {
+			error = EHOSTUNREACH;
+			goto done;
+		} else if (rte->rt_ifp == NULL || rte->rt_ifp == V_loif ||
+		    RT_LINK_IS_UP(rte->rt_ifp) == 0) {
+			RTFREE_LOCKED(rte);
+			error = EHOSTUNREACH;
+			goto done;
+		}
 		RT_UNLOCK(rte);
+		break;
+	default:
+		error = ENETUNREACH;
+		goto done;
+	}
 
+	/* Step 2 - find outgoing network interface */
+	switch (type) {
+	case 0:
+		/* source check */
 		ifp = ip6_dev_find(addr->net, src_in->sin6_addr);
 		if (ifp == NULL) {
-			RTFREE(rte);
 			error = ENETUNREACH;
-			goto done;
+			goto error_rt_free;
 		} else if (ifp != rte->rt_ifp) {
 			error = ENETUNREACH;
-			goto failure;
+			goto error_put_ifp;
 		}
-	} else {
-		struct sockaddr *saddr;
-
+		break;
+	case 1:
+		/* get destination network interface from route */
 		ifp = rte->rt_ifp;
 		dev_hold(ifp);
-
 		saddr = rte->rt_ifa->ifa_addr;
+
+		src_port = src_in->sin6_port;
 		memcpy(src_in, saddr, rdma_addr_size(saddr));
-		RT_UNLOCK(rte);
+		src_in->sin6_port = src_port;	/* preserve port number */
+		break;
+	default:
+		break;
 	}
 
 	/*
-	 * Resolve destination MAC address
+	 * Step 3 - resolve destination MAC address
 	 */
 	if (IN6_IS_ADDR_MULTICAST(&dst_tmp.sin6_addr)) {
-		error = addr_resolve_multi(edst, ifp, (struct sockaddr *)&dst_tmp);
+		error = addr_resolve_multi(edst, ifp,
+		    (struct sockaddr *)&dst_tmp);
 		if (error != 0)
-			goto failure;
+			goto error_put_ifp;
 	} else {
 		bool is_gw = (rte->rt_flags & RTF_GATEWAY) != 0;
 		memset(edst, 0, sizeof(edst));
@@ -421,29 +475,34 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
 		    rte->rt_gateway : (const struct sockaddr *)&dst_tmp,
 		    edst, NULL, NULL);
 		if (error != 0)
-			goto failure;
+			goto error_put_ifp;
 		else if (is_gw != 0)
 			addr->network = RDMA_NETWORK_IPV6;
 	}
 
 	/*
-	 * Copy destination and source MAC addresses
+	 * Step 4 - copy destination and source MAC addresses
 	 */
 	error = -rdma_copy_addr(addr, ifp, edst);
-	if (error != 0) {
-failure:
-		dev_put(ifp);
+	if (error != 0)
+		goto error_put_ifp;
 
-		if (error == EWOULDBLOCK || error == EAGAIN)
-			error = ENODATA;
-	} else {
-		*ifpp = ifp;
-	}
+	if (rte != NULL)
+		RTFREE(rte);
+
+	*ifpp = ifp;
+
+	goto done;
+
+error_put_ifp:
+	dev_put(ifp);
+error_rt_free:
 	RTFREE(rte);
 done:
-	sa6_recoverscope(&dst_tmp);
-	sa6_recoverscope(src_in);
+	CURVNET_RESTORE();
 
+	if (error == EWOULDBLOCK || error == EAGAIN)
+		error = ENODATA;
 	return (-error);
 }
 #else



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709161624.v8GGOdS8047118>