2008-02-18 18:36:29

by Chuck Lever III

[permalink] [raw]
Subject: [PATCH 13/17] text-based mount: support IPv6 addresses in get_client_address() function

The NFSv4 clientaddr= mount option communicates the client's local IP
address to the kernel. This address is then provided to the server as
the client's callback address. If the admin doesn't specify a clientaddr=
option, the mount command uses the get_client_address() function to
detect the client's local IP address.

Add support to the get_client_address() function for IPv6 addressing,
and rename the function to identify it as a local API. Note there's
nothing specific to IPv6 here; we just make the API family-agnostic.

Signed-off-by: Chuck Lever <[email protected]>
---

utils/mount/network.c | 17 ++++++++++-------
utils/mount/network.h | 2 +-
utils/mount/stropts.c | 4 +++-
3 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/utils/mount/network.c b/utils/mount/network.c
index 5e6d17d..6c29e7c 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -860,29 +860,32 @@ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
}

/**
- * get_client_address - acquire our local network address
+ * nfs_client_address - acquire our local network address
* @saddr: server's address
- * @caddr: filled in with our network address
+ * @laddr: filled in with our local network address
+ * @laddr_len: IN: length of buffer to fill in; OUT: length of filled-in address
*
* Discover a network address that the server will use to call us back.
* On multi-homed clients, this address depends on which NIC we use to
* route requests to the server.
*
- * Use a connected datagram socket so as not to leave a socket in TIME_WAIT.
+ * A connected datagram socket is used to prevent leaving the socket
+ * in TIME_WAIT, to conserve the ephemeral port number space. This helps
+ * reduce failed socket binds during mount storms.
*
* Returns one if successful, otherwise zero.
*/
-int get_client_address(struct sockaddr_in *saddr, struct sockaddr_in *caddr)
+int nfs_client_address(const struct sockaddr *saddr, struct sockaddr *laddr,
+ socklen_t *laddr_len)
{
- socklen_t len = sizeof(*caddr);
int sock, err;

- sock = nfs_getsocket((struct sockaddr *)saddr, IPPROTO_UDP,
+ sock = nfs_getsocket(saddr, IPPROTO_UDP,
CONNECT_TIMEOUT, FALSE, TRUE);
if (sock == RPC_ANYSOCK)
return 0;

- err = getsockname(sock, caddr, &len);
+ err = getsockname(sock, laddr, laddr_len);
if (err && verbose)
nfs_error(_("%s: error acquiring client's local address: %s"),
progname, strerror(errno));
diff --git a/utils/mount/network.h b/utils/mount/network.h
index 99ecc1e..7cabb16 100644
--- a/utils/mount/network.h
+++ b/utils/mount/network.h
@@ -48,7 +48,7 @@ static const struct timeval RETRY_TIMEOUT = { 3, 0 };

int probe_bothports(clnt_addr_t *, clnt_addr_t *);
int nfs_gethostbyname(const char *, struct sockaddr_in *);
-int get_client_address(struct sockaddr_in *, struct sockaddr_in *);
+int nfs_client_address(const struct sockaddr *, 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,
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
index cadb1f4..6293766 100644
--- a/utils/mount/stropts.c
+++ b/utils/mount/stropts.c
@@ -178,12 +178,14 @@ static int append_clientaddr_option(struct sockaddr_in *saddr,
struct mount_options *options)
{
struct sockaddr_in my_addr;
+ socklen_t len = sizeof(my_addr);
char new_option[32];

if (po_contains(options, "clientaddr") == PO_SUCCEEDED)
return 1;

- if (!get_client_address(saddr, &my_addr))
+ if (!nfs_client_address((struct sockaddr *)saddr,
+ (struct sockaddr *)&my_addr, &len))
return 0;

snprintf(new_option, sizeof(new_option) - 1,