public inbox for linux-nfs@vger.kernel.org
 help / color / mirror / Atom feed
From: Chuck Lever <chuck.lever@oracle.com>
To: steved@redhat.com
Cc: linux-nfs@vger.kernel.org
Subject: [PATCH 04/14] text-based mount command: get_client_address support for IPv6
Date: Fri, 11 Jul 2008 16:34:34 -0400	[thread overview]
Message-ID: <20080711203434.478.20200.stgit@tarkus.1015granger.net> (raw)
In-Reply-To: <20080711203322.478.52095.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>

Introduce IPv6-enabled version of get_client_address.  The legacy mount
command could use this eventually as well.

If this new function fails to discover an appropriate callback address, it
fills in an ANY address to indicate to the server that it should not call the
client back (ie delegations are disabled in this case).

The user can specify a callback address via the clientaddr= mount option in
this case to enable delegation.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---

 utils/mount/network.c |  118 +++++++++++++++++++++++++++++++++++++++++++++++++
 utils/mount/network.h |    2 +
 2 files changed, 120 insertions(+), 0 deletions(-)


diff --git a/utils/mount/network.c b/utils/mount/network.c
index 3f2721b..849ce1d 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -918,3 +918,121 @@ int get_client_address(struct sockaddr_in *saddr, struct sockaddr_in *caddr)
 	}
 	return 1;
 }
+
+/*
+ * Try a getsockname() on a connected datagram socket.
+ *
+ * Returns 1 and fills in @buf if successful; otherwise, zero.
+ *
+ * A connected datagram socket prevents leaving a socket in TIME_WAIT.
+ * This conserves the ephemeral port number space, helping reduce failed
+ * socket binds during mount storms.
+ */
+static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen,
+			   struct sockaddr *buf, socklen_t *buflen)
+{
+	struct sockaddr_in sin = {
+		.sin_family		= AF_INET,
+		.sin_addr.s_addr	= htonl(INADDR_ANY),
+	};
+	struct sockaddr_in6 sin6 = {
+		.sin6_family		= AF_INET6,
+		.sin6_addr		= IN6ADDR_ANY_INIT,
+	};
+	int sock;
+
+	sock = socket(sap->sa_family, SOCK_DGRAM, IPPROTO_UDP);
+	if (sock < 0)
+		return 0;
+
+	switch (sap->sa_family) {
+	case AF_INET:
+		if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+			close(sock);
+			return 0;
+		}
+		break;
+	case AF_INET6:
+		if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
+			close(sock);
+			return 0;
+		}
+		break;
+	default:
+		errno = EAFNOSUPPORT;
+		return 0;
+	}
+
+	if (connect(sock, sap, salen) < 0) {
+		close(sock);
+		return 0;
+	}
+
+	return !getsockname(sock, buf, buflen);
+}
+
+/*
+ * Try to generate an address that prevents the server from calling us.
+ *
+ * Returns 1 and fills in @buf if successful; otherwise, zero.
+ */
+static int nfs_ca_gai(const struct sockaddr *sap, const socklen_t salen,
+		      struct sockaddr *buf, socklen_t *buflen)
+{
+	struct addrinfo *gai_results;
+	struct addrinfo gai_hint = {
+		.ai_family	= sap->sa_family,
+		.ai_flags	= AI_PASSIVE,	/* ANYADDR */
+	};
+
+	if (getaddrinfo(NULL, "", &gai_hint, &gai_results))
+		return 0;
+
+	*buflen = gai_results->ai_addrlen;
+	memcpy(buf, gai_results->ai_addr, *buflen);
+
+	freeaddrinfo(gai_results);
+
+	return 1;
+}
+
+/**
+ * nfs_callback_address - acquire our local network address
+ * @sap: pointer to address of remote
+ * @sap_len: length of address
+ * @buf: pointer to buffer to be filled in with local network address
+ * @buflen: IN: length of buffer to fill in; OUT: length of filled-in address
+ *
+ * Discover a network address that an NFSv4 server can use to call us back.
+ * On multi-homed clients, this address depends on which NIC we use to
+ * route requests to the server.
+ *
+ * Returns 1 and fills in @buf if an unambiguous local address is
+ * available; returns 1 and fills in an appropriate ANYADDR address
+ * if a local address isn't available; otherwise, returns zero.
+ */
+int nfs_callback_address(const struct sockaddr *sap, const socklen_t salen,
+			 struct sockaddr *buf, socklen_t *buflen)
+{
+	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf;
+
+	if (nfs_ca_sockname(sap, salen, buf, buflen) == 0)
+		if (nfs_ca_gai(sap, salen, buf, buflen) == 0)
+			goto out_failed;
+
+	/*
+	 * The server can't use an interface ID that was generated
+	 * here on the client, so always clear sin6_scope_id.
+	 */
+	if (sin6->sin6_family == AF_INET6)
+		sin6->sin6_scope_id = 0;
+
+	return 1;
+
+out_failed:
+	*buflen = 0;
+	if (verbose)
+		nfs_error(_("%s: failed to construct callback address"));
+	return 0;
+
+}
diff --git a/utils/mount/network.h b/utils/mount/network.h
index 8da7e20..2f4ff3a 100644
--- a/utils/mount/network.h
+++ b/utils/mount/network.h
@@ -58,6 +58,8 @@ int nfs_string_to_sockaddr(const char *, const size_t,
 int nfs_present_sockaddr(const struct sockaddr *,
 			 const socklen_t, char *, const size_t);
 int get_client_address(struct sockaddr_in *, struct sockaddr_in *);
+int nfs_callback_address(const struct sockaddr *, const socklen_t,
+		struct sockaddr *, socklen_t *);
 int nfs_call_umount(clnt_addr_t *, dirpath *);
 int clnt_ping(struct sockaddr_in *, const unsigned long,
 		const unsigned long, const unsigned int,


  parent reply	other threads:[~2008-07-11 20:35 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-07-11 20:34 [PATCH 00/14] Support for mounting NFSv4 servers over IPv6 Chuck Lever
     [not found] ` <20080711203322.478.52095.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-07-11 20:34   ` [PATCH 01/14] nfs-utils: Introduce new ./configure option: "--enable-ipv6" Chuck Lever
2008-07-11 20:34   ` [PATCH 02/14] text-based mount command: Add headers needed for IPv6 support Chuck Lever
2008-07-11 20:34   ` [PATCH 03/14] mount command: Add functions to manage addresses in string form Chuck Lever
2008-07-11 20:34   ` Chuck Lever [this message]
2008-07-11 20:34   ` [PATCH 05/14] text-based mount command: Add helper to construct network addresses Chuck Lever
2008-07-11 20:34   ` [PATCH 06/14] text-based mount command: "addr=" option support for IPv6 addresses Chuck Lever
2008-07-11 20:34   ` [PATCH 07/14] text-based mount command: "clientaddr=" " Chuck Lever
2008-07-11 20:34   ` [PATCH 08/14] text-based mount command: "mounthost=" " Chuck Lever
2008-07-11 20:35   ` [PATCH 09/14] text-based mount command: Add IPv6 support to set_mandatory_options Chuck Lever
2008-07-11 20:35   ` [PATCH 10/14] text-based mount command: Support raw IPv6 address hostnames Chuck Lever
2008-07-11 20:35   ` [PATCH 11/14] text-based mount command: Remove unused IPv4-only functions Chuck Lever
2008-07-11 20:35   ` [PATCH 12/14] text-based mount options: rename functions in stropts.c Chuck Lever
2008-07-11 20:35   ` [PATCH 13/14] text-based mount command: remove unnecessary headers from stropts.c Chuck Lever
2008-07-11 20:35   ` [PATCH 14/14] mount command: Remove RPC headers from network.h Chuck Lever
2008-07-15 19:31   ` [PATCH 00/14] Support for mounting NFSv4 servers over IPv6 Steve Dickson
  -- strict thread matches above, loose matches on Subject: below --
2008-07-10  0:37 Chuck Lever
     [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-07-10  0:37   ` [PATCH 04/14] text-based mount command: get_client_address support for IPv6 Chuck Lever
     [not found]     ` <20080710003723.6137.51761.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-07-10 19:30       ` J. Bruce Fields
2008-07-10 19:36         ` Chuck Lever
2008-07-10 19:43           ` J. Bruce Fields
2008-07-10 20:35             ` Chuck Lever
     [not found]               ` <76bd70e30807101335y54f8b479v39953a772e08e88c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-07-11 19:06                 ` J. Bruce Fields
2008-07-11 19:16                   ` Chuck Lever

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080711203434.478.20200.stgit@tarkus.1015granger.net \
    --to=chuck.lever@oracle.com \
    --cc=linux-nfs@vger.kernel.org \
    --cc=steved@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox