* [PATCH 00/14] Support for mounting NFSv4 servers over IPv6
@ 2008-07-10 0:37 Chuck Lever
[not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
0 siblings, 1 reply; 22+ messages in thread
From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
Hi Steve-
Just for fun, here is the latest version of the patches that add support to
the text-based mount.nfs command for mounting NFSv4 servers over IPv6. This
patch set applies on top of the patches I posted here last week.
It was suggested that these be included in the next release of
nfs-utils, 1.1.3. Kernel support for these features (such as handling raw
IPv6 NFS server addresses properly when mounting) is planned for 2.6.27, so
inclusion of these patches would allow wider testing during .27's rc period.
Mounting NFSv2/v3 servers over IPv6 is more complex. It requires support
for a scalable rpcbind/portmap client built into nfs-utils, thus it is not
included in the present patch series. Anyone interested in looking at my
current prototype for this can check out:
http://git.linux-nfs.org/?p=cel/nfs-utils.git;a=summary
It includes all the patches in this series and the patches I posted last
week for nfs-utils 1.1.3, client-side support for NFSv2/v3 mounting and
unmounting over IPv6, a prototype IPv6-enabled sm-notify command, and
updates to nfs(5) describing IPv6 support for the NFS client.
For what it's worth, I'll be on holiday next week, but I can field any
questions or comments before this Saturday, or when I return.
---
Chuck Lever (14):
mount command: Remove RPC headers from network.h
text-based mount command: remove unnecessary headers from stropts.c
text-based mount options: rename functions in stropts.c
text-based mount command: Remove unused IPv4-only functions
text-based mount command: Support raw IPv6 address hostnames
text-based mount command: Add IPv6 support to set_mandatory_options
text-based mount command: "mounthost=" option support for IPv6 addresses
text-based mount command: "clientaddr=" option support for IPv6 addresses
text-based mount command: "addr=" option support for IPv6 addresses
text-based mount command: Add helper to construct network addresses
text-based mount command: get_client_address support for IPv6
mount command: Add functions to manage addresses in string form
text-based mount command: Add headers needed for IPv6 support
nfs-utils: Introduce new ./configure option: "--enable-ipv6"
configure.ac | 29 ++++++
utils/mount/Makefile.am | 6 +
utils/mount/error.c | 2
utils/mount/mount.c | 1
utils/mount/network.c | 237 +++++++++++++++++++++++++++++++++++++++++------
utils/mount/network.h | 17 +--
utils/mount/nfs4mount.c | 2
utils/mount/nfsmount.c | 7 +
utils/mount/nfsumount.c | 35 +++----
utils/mount/parse_dev.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++
utils/mount/parse_dev.h | 28 ++++++
utils/mount/stropts.c | 229 ++++++++++++++++++---------------------------
12 files changed, 617 insertions(+), 206 deletions(-)
create mode 100644 utils/mount/parse_dev.c
create mode 100644 utils/mount/parse_dev.h
--
Signature
^ permalink raw reply [flat|nested] 22+ messages in thread[parent not found: <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>]
* [PATCH 01/14] nfs-utils: Introduce new ./configure option: "--enable-ipv6" [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> @ 2008-07-10 0:37 ` Chuck Lever 2008-07-10 0:37 ` [PATCH 02/14] text-based mount command: Add headers needed for IPv6 support Chuck Lever ` (12 subsequent siblings) 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw) To: steved; +Cc: linux-nfs We want to continue to support building nfs-utils on systems that do not have IPv6-enabled RPC libraries and headers installed, so add a ./configure switch that allows distros to disable IPv6 functionality. This patch introduces the nfs-utils autotools configuration to the library and header dependencies that will be required in subsequent patches. Later patches can then be reordered more easily if these new dependencies are added in one heap. For now, --enable-ipv6 defaults to "no", so this patch should not result in any behavioral changes to the nfs-utils build process, by default. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- configure.ac | 29 ++++++++++++++++++++++++++++- 1 files changed, 28 insertions(+), 1 deletions(-) diff --git a/configure.ac b/configure.ac index d508c28..e6bcb62 100644 --- a/configure.ac +++ b/configure.ac @@ -127,6 +127,18 @@ AC_ARG_ENABLE(mount, enable_mount=$enableval, enable_mount=yes) AM_CONDITIONAL(CONFIG_MOUNT, [test "$enable_mount" = "yes"]) +AC_ARG_ENABLE(ipv6, + [AC_HELP_STRING([--enable-ipv6], + [enable support for IPv6 @<:@default=no@:>@])], + enable_ipv6=$enableval, + enable_ipv6=no) + if test "$enable_ipv6" = yes; then + AC_DEFINE(IPV6_SUPPORTED, 1, [Define this if you want IPv6 support compiled in]) + else + enable_ipv6= + fi + AC_SUBST(enable_ipv6) + AM_CONDITIONAL(CONFIG_IPV6, [test "$enable_ipv6" = "yes"]) # Check whether user wants TCP wrappers support AC_TCP_WRAPPERS @@ -237,6 +249,17 @@ if test "$enable_gss" = yes; then fi +if test "$enable_ipv6" = yes; then + AC_CHECK_FUNC(inet_ntop, , , + AC_MSG_ERROR(Function 'inet_ntop' not found.)) + AC_CHECK_FUNC(getnameinfo, , , + AC_MSG_ERROR(Function 'getnameinfo' not found.)) + AC_CHECK_LIB(tirpc, clnt_tli_create, , + AC_MSG_ERROR([libtirpc needed for IPv6 support])) + AC_CHECK_HEADERS(tirpc/netconfig.h, , + AC_MSG_ERROR([libtirpc-devel needed for IPv6 support])) +fi + dnl ************************************************************* dnl Check for headers dnl ************************************************************* @@ -245,7 +268,7 @@ AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h \ stdlib.h string.h sys/file.h sys/ioctl.h sys/mount.h \ sys/param.h sys/socket.h sys/time.h sys/vfs.h \ syslog.h unistd.h com_err.h et/com_err.h \ - ifaddrs.h]) + ifaddrs.h tirpc/netconfig.h]) dnl ************************************************************* dnl Checks for typedefs, structures, and compiler characteristics @@ -281,6 +304,10 @@ AC_FUNC_STAT AC_FUNC_VPRINTF AC_CHECK_FUNCS([alarm atexit dup2 fdatasync ftruncate getcwd \ gethostbyaddr gethostbyname gethostname getmntent \ + inet_ntop getnameinfo getrpcbyname \ + bindresvport_sa getnetconfig \ + clnt_create clnt_create_timed \ + clnt_tli_create clnt_vc_create clnt_dg_create xdr_rpcb \ gettimeofday hasmntopt inet_ntoa innetgr memset mkdir pathconf \ realpath rmdir select socket strcasecmp strchr strdup \ strerror strrchr strtol strtoul sigprocmask]) ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 02/14] text-based mount command: Add headers needed for IPv6 support [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> 2008-07-10 0:37 ` [PATCH 01/14] nfs-utils: Introduce new ./configure option: "--enable-ipv6" Chuck Lever @ 2008-07-10 0:37 ` Chuck Lever 2008-07-10 0:37 ` [PATCH 03/14] mount command: Add functions to manage addresses in string form Chuck Lever ` (11 subsequent siblings) 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw) To: steved; +Cc: linux-nfs Add #include directives for additional header files needed to support IPv6 networking. This is a separate patch so subsequent patches can be reordered without collision. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/network.c | 5 ++++- utils/mount/stropts.c | 3 +++ 2 files changed, 7 insertions(+), 1 deletions(-) diff --git a/utils/mount/network.c b/utils/mount/network.c index 30a4d40..c9fd548 100644 --- a/utils/mount/network.c +++ b/utils/mount/network.c @@ -33,10 +33,13 @@ #include <errno.h> #include <netdb.h> #include <time.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> #include <rpc/rpc.h> #include <rpc/pmap_prot.h> #include <rpc/pmap_clnt.h> -#include <sys/socket.h> #include "xcommon.h" #include "mount.h" diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index 34b4134..a9c0b50 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -33,8 +33,11 @@ #include <errno.h> #include <netdb.h> #include <time.h> + #include <sys/socket.h> #include <sys/mount.h> +#include <netinet/in.h> +#include <arpa/inet.h> #include "xcommon.h" #include "mount.h" ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 03/14] mount command: Add functions to manage addresses in string form [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> 2008-07-10 0:37 ` [PATCH 01/14] nfs-utils: Introduce new ./configure option: "--enable-ipv6" Chuck Lever 2008-07-10 0:37 ` [PATCH 02/14] text-based mount command: Add headers needed for IPv6 support Chuck Lever @ 2008-07-10 0:37 ` Chuck Lever 2008-07-10 0:37 ` [PATCH 04/14] text-based mount command: get_client_address support for IPv6 Chuck Lever ` (10 subsequent siblings) 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw) To: steved; +Cc: linux-nfs Introduce two new functions to convert a sockaddr to a presentation format string and back. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/network.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ utils/mount/network.h | 4 ++ 2 files changed, 96 insertions(+), 0 deletions(-) diff --git a/utils/mount/network.c b/utils/mount/network.c index c9fd548..3f2721b 100644 --- a/utils/mount/network.c +++ b/utils/mount/network.c @@ -215,6 +215,98 @@ int nfs_gethostbyname(const char *hostname, struct sockaddr_in *sin) (struct sockaddr *)sin, &len); } +/** + * nfs_string_to_sockaddr - convert string address to sockaddr + * @address: pointer to presentation format address to convert + * @addrlen: length of presentation address + * @sap: pointer to socket address buffer to fill in + * @salen: IN: length of address buffer + * OUT: length of converted socket address + * + * Convert a presentation format address string to a socket address. + * Similar to nfs_name_to_address(), but the DNS query is squelched, + * and won't make any noise if the getaddrinfo() call fails. + * + * Returns 1 and fills in @sap and @salen if successful; otherwise zero. + * + * See RFC 4038 section 5.1 or RFC 3513 section 2.2 for more details + * on presenting IPv6 addresses as text strings. + */ +int nfs_string_to_sockaddr(const char *address, const size_t addrlen, + struct sockaddr *sap, socklen_t *salen) +{ + struct addrinfo *gai_results; + struct addrinfo gai_hint = { + .ai_flags = AI_NUMERICHOST, + }; + socklen_t len = *salen; + int ret = 0; + + *salen = 0; + + if (getaddrinfo(address, NULL, &gai_hint, &gai_results) == 0) { + switch (gai_results->ai_addr->sa_family) { + case AF_INET: + case AF_INET6: + if (len >= gai_results->ai_addrlen) { + *salen = gai_results->ai_addrlen; + memcpy(sap, gai_results->ai_addr, *salen); + ret = 1; + } + break; + } + freeaddrinfo(gai_results); + } + + return ret; +} + +/** + * nfs_present_sockaddr - convert sockaddr to string + * @sap: pointer to socket address to convert + * @salen: length of socket address + * @buf: pointer to buffer to fill in + * @buflen: length of buffer + * + * Convert the passed-in sockaddr-style address to presentation format. + * The presentation format address is placed in @buf and is + * '\0'-terminated. + * + * Returns 1 if successful; otherwise zero. + * + * See RFC 4038 section 5.1 or RFC 3513 section 2.2 for more details + * on presenting IPv6 addresses as text strings. + */ +int nfs_present_sockaddr(const struct sockaddr *sap, const socklen_t salen, + char *buf, const size_t buflen) +{ +#ifdef HAVE_GETNAMEINFO + int result; + + result = getnameinfo(sap, salen, buf, buflen, + NULL, 0, NI_NUMERICHOST); + if (!result) + return 1; + + nfs_error(_("%s: invalid server address: %s"), progname, + gai_strerror(result)); + return 0; +#else /* HAVE_GETNAMEINFO */ + char *addr; + + if (sap->sa_family == AF_INET) { + addr = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr); + if (addr && strlen(addr) < buflen) { + strcpy(buf, addr); + return 1; + } + } + + nfs_error(_("%s: invalid server address"), progname); + return 0; +#endif /* HAVE_GETNAMEINFO */ +} + /* * Attempt to connect a socket, but time out after "timeout" seconds. * diff --git a/utils/mount/network.h b/utils/mount/network.h index 9de13b5..8da7e20 100644 --- a/utils/mount/network.h +++ b/utils/mount/network.h @@ -53,6 +53,10 @@ int probe_bothports(clnt_addr_t *, clnt_addr_t *); int nfs_gethostbyname(const char *, struct sockaddr_in *); int nfs_name_to_address(const char *, const sa_family_t, struct sockaddr *, socklen_t *); +int nfs_string_to_sockaddr(const char *, const size_t, + struct sockaddr *, socklen_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_call_umount(clnt_addr_t *, dirpath *); int clnt_ping(struct sockaddr_in *, const unsigned long, ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 04/14] text-based mount command: get_client_address support for IPv6 [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (2 preceding siblings ...) 2008-07-10 0:37 ` [PATCH 03/14] mount command: Add functions to manage addresses in string form Chuck Lever @ 2008-07-10 0:37 ` Chuck Lever [not found] ` <20080710003723.6137.51761.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> 2008-07-10 0:37 ` [PATCH 05/14] text-based mount command: Add helper to construct network addresses Chuck Lever ` (9 subsequent siblings) 13 siblings, 1 reply; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw) To: steved; +Cc: linux-nfs Introduce IPv6-enabled version of get_client_address. The legacy mount command could use this eventually as well. I don't remember how to tell an NFSv4 server to disable the callback channel: whether an ANY address is passed with SETCLIENTID, or a loopback address is passed. The patch allows either to be used with a compile-time switch. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/network.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ utils/mount/network.h | 2 + 2 files changed, 124 insertions(+), 0 deletions(-) diff --git a/utils/mount/network.c b/utils/mount/network.c index 3f2721b..128d7f7 100644 --- a/utils/mount/network.c +++ b/utils/mount/network.c @@ -918,3 +918,125 @@ 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, +#ifdef GENERATE_LOOPBACK_ADDRESS + .ai_flags = 0, /* loopback */ +#else + .ai_flags = AI_PASSIVE, /* ANYADDR */ +#endif + }; + + 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, ^ permalink raw reply related [flat|nested] 22+ messages in thread
[parent not found: <20080710003723.6137.51761.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>]
* Re: [PATCH 04/14] text-based mount command: get_client_address support for IPv6 [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 0 siblings, 1 reply; 22+ messages in thread From: J. Bruce Fields @ 2008-07-10 19:30 UTC (permalink / raw) To: Chuck Lever; +Cc: steved, linux-nfs On Wed, Jul 09, 2008 at 08:37:24PM -0400, Chuck Lever wrote: > Introduce IPv6-enabled version of get_client_address. The legacy mount > command could use this eventually as well. > > I don't remember how to tell an NFSv4 server to disable the callback > channel: whether an ANY address is passed with SETCLIENTID, or a > loopback address is passed. The patch allows either to be used with a > compile-time switch. I would have thought INADDR_ANY. But in any case we should just pick one.... --b. > > Signed-off-by: Chuck Lever <chuck.lever@oracle.com> > --- > > utils/mount/network.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ > utils/mount/network.h | 2 + > 2 files changed, 124 insertions(+), 0 deletions(-) > > diff --git a/utils/mount/network.c b/utils/mount/network.c > index 3f2721b..128d7f7 100644 > --- a/utils/mount/network.c > +++ b/utils/mount/network.c > @@ -918,3 +918,125 @@ 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, > +#ifdef GENERATE_LOOPBACK_ADDRESS > + .ai_flags = 0, /* loopback */ > +#else > + .ai_flags = AI_PASSIVE, /* ANYADDR */ > +#endif > + }; > + > + 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, > > -- > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 04/14] text-based mount command: get_client_address support for IPv6 2008-07-10 19:30 ` J. Bruce Fields @ 2008-07-10 19:36 ` Chuck Lever 2008-07-10 19:43 ` J. Bruce Fields 0 siblings, 1 reply; 22+ messages in thread From: Chuck Lever @ 2008-07-10 19:36 UTC (permalink / raw) To: J. Bruce Fields; +Cc: steved, linux-nfs On Jul 10, 2008, at 3:30 PM, J. Bruce Fields wrote: > On Wed, Jul 09, 2008 at 08:37:24PM -0400, Chuck Lever wrote: >> Introduce IPv6-enabled version of get_client_address. The legacy >> mount >> command could use this eventually as well. >> >> I don't remember how to tell an NFSv4 server to disable the callback >> channel: whether an ANY address is passed with SETCLIENTID, or a >> loopback address is passed. The patch allows either to be used >> with a >> compile-time switch. > > I would have thought INADDR_ANY. But in any case we should just pick > one.... Well, yes, but we should pick the "correct" one. :-) The patch does it this way just to make a note of this issue so we can make a decision before committing this upstream. Does RFC 3530 have any recommendation about this? > > > --b. > >> >> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> >> --- >> >> utils/mount/network.c | 122 +++++++++++++++++++++++++++++++++++++++ >> ++++++++++ >> utils/mount/network.h | 2 + >> 2 files changed, 124 insertions(+), 0 deletions(-) >> >> diff --git a/utils/mount/network.c b/utils/mount/network.c >> index 3f2721b..128d7f7 100644 >> --- a/utils/mount/network.c >> +++ b/utils/mount/network.c >> @@ -918,3 +918,125 @@ 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, >> +#ifdef GENERATE_LOOPBACK_ADDRESS >> + .ai_flags = 0, /* loopback */ >> +#else >> + .ai_flags = AI_PASSIVE, /* ANYADDR */ >> +#endif >> + }; >> + >> + 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, >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux- >> nfs" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html -- Chuck Lever chuck[dot]lever[at]oracle[dot]com ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 04/14] text-based mount command: get_client_address support for IPv6 2008-07-10 19:36 ` Chuck Lever @ 2008-07-10 19:43 ` J. Bruce Fields 2008-07-10 20:35 ` Chuck Lever 0 siblings, 1 reply; 22+ messages in thread From: J. Bruce Fields @ 2008-07-10 19:43 UTC (permalink / raw) To: Chuck Lever; +Cc: steved, linux-nfs On Thu, Jul 10, 2008 at 03:36:21PM -0400, Chuck Lever wrote: > On Jul 10, 2008, at 3:30 PM, J. Bruce Fields wrote: >> On Wed, Jul 09, 2008 at 08:37:24PM -0400, Chuck Lever wrote: >>> Introduce IPv6-enabled version of get_client_address. The legacy >>> mount >>> command could use this eventually as well. >>> >>> I don't remember how to tell an NFSv4 server to disable the callback >>> channel: whether an ANY address is passed with SETCLIENTID, or a >>> loopback address is passed. The patch allows either to be used with >>> a >>> compile-time switch. >> >> I would have thought INADDR_ANY. But in any case we should just pick >> one.... > > Well, yes, but we should pick the "correct" one. :-) The patch does it > this way just to make a note of this issue so we can make a decision > before committing this upstream. > > Does RFC 3530 have any recommendation about this? Not that I can find on a quick skim. I don't see why the spec would forbid running over loopback, though, in which case a loopback callback address would make sense. And I assume INADDR_ANY is always meaningless as a destination address, so is a logical way to tell the server it can't call back to you. --b. > >> >> >> --b. >> >>> >>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> >>> --- >>> >>> utils/mount/network.c | 122 +++++++++++++++++++++++++++++++++++++++ >>> ++++++++++ >>> utils/mount/network.h | 2 + >>> 2 files changed, 124 insertions(+), 0 deletions(-) >>> >>> diff --git a/utils/mount/network.c b/utils/mount/network.c >>> index 3f2721b..128d7f7 100644 >>> --- a/utils/mount/network.c >>> +++ b/utils/mount/network.c >>> @@ -918,3 +918,125 @@ 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, >>> +#ifdef GENERATE_LOOPBACK_ADDRESS >>> + .ai_flags = 0, /* loopback */ >>> +#else >>> + .ai_flags = AI_PASSIVE, /* ANYADDR */ >>> +#endif >>> + }; >>> + >>> + 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, >>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" >>> in >>> the body of a message to majordomo@vger.kernel.org >>> More majordomo info at http://vger.kernel.org/majordomo-info.html > > -- > Chuck Lever > chuck[dot]lever[at]oracle[dot]com > > > ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 04/14] text-based mount command: get_client_address support for IPv6 2008-07-10 19:43 ` J. Bruce Fields @ 2008-07-10 20:35 ` Chuck Lever [not found] ` <76bd70e30807101335y54f8b479v39953a772e08e88c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 22+ messages in thread From: Chuck Lever @ 2008-07-10 20:35 UTC (permalink / raw) To: J. Bruce Fields; +Cc: steved, linux-nfs On Thu, Jul 10, 2008 at 3:43 PM, J. Bruce Fields <bfields@fieldses.org> wrote: > On Thu, Jul 10, 2008 at 03:36:21PM -0400, Chuck Lever wrote: >> On Jul 10, 2008, at 3:30 PM, J. Bruce Fields wrote: >>> On Wed, Jul 09, 2008 at 08:37:24PM -0400, Chuck Lever wrote: >>>> Introduce IPv6-enabled version of get_client_address. The legacy >>>> mount >>>> command could use this eventually as well. >>>> >>>> I don't remember how to tell an NFSv4 server to disable the callback >>>> channel: whether an ANY address is passed with SETCLIENTID, or a >>>> loopback address is passed. The patch allows either to be used with >>>> a >>>> compile-time switch. >>> >>> I would have thought INADDR_ANY. But in any case we should just pick >>> one.... >> >> Well, yes, but we should pick the "correct" one. :-) The patch does it >> this way just to make a note of this issue so we can make a decision >> before committing this upstream. >> >> Does RFC 3530 have any recommendation about this? > > Not that I can find on a quick skim. Is it clarified in the NFSv4.1 draft? > I don't see why the spec would forbid running over loopback, though, in > which case a loopback callback address would make sense. And I assume > INADDR_ANY is always meaningless as a destination address, so is a > logical way to tell the server it can't call back to you. Yep, I agree. I recall a few years back at a CITI bake-a-thon there was a certain server vendor who had trouble with loopback callback addresses, probably because their implementation was server-only, so an NFSv4 callback from loopback would make no sense for them. The client in this case was sending a loopback callback address because it hadn't implemented a callback service and wanted to prevent the server from calling it back. Do we have a high degree of certainty that sending an ANY address is appropriate if the client can't determine a reasonable callback address to send with SETCLIENTID? Is it at least OK for Linux's NFSv4 server? If we think this might be a problem, I can change all this back to simply failing the mount request when the mount.nfs command can't figure out a valid callback address. >>>> >>>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> >>>> --- >>>> >>>> utils/mount/network.c | 122 +++++++++++++++++++++++++++++++++++++++ >>>> ++++++++++ >>>> utils/mount/network.h | 2 + >>>> 2 files changed, 124 insertions(+), 0 deletions(-) >>>> >>>> diff --git a/utils/mount/network.c b/utils/mount/network.c >>>> index 3f2721b..128d7f7 100644 >>>> --- a/utils/mount/network.c >>>> +++ b/utils/mount/network.c >>>> @@ -918,3 +918,125 @@ 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, >>>> +#ifdef GENERATE_LOOPBACK_ADDRESS >>>> + .ai_flags = 0, /* loopback */ >>>> +#else >>>> + .ai_flags = AI_PASSIVE, /* ANYADDR */ >>>> +#endif >>>> + }; >>>> + >>>> + 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, >>>> -- Chuck Lever ^ permalink raw reply [flat|nested] 22+ messages in thread
[parent not found: <76bd70e30807101335y54f8b479v39953a772e08e88c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 04/14] text-based mount command: get_client_address support for IPv6 [not found] ` <76bd70e30807101335y54f8b479v39953a772e08e88c-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2008-07-11 19:06 ` J. Bruce Fields 2008-07-11 19:16 ` Chuck Lever 0 siblings, 1 reply; 22+ messages in thread From: J. Bruce Fields @ 2008-07-11 19:06 UTC (permalink / raw) To: chucklever; +Cc: steved, linux-nfs On Thu, Jul 10, 2008 at 04:35:57PM -0400, Chuck Lever wrote: > On Thu, Jul 10, 2008 at 3:43 PM, J. Bruce Fields <bfields@fieldses.org> wrote: > > On Thu, Jul 10, 2008 at 03:36:21PM -0400, Chuck Lever wrote: > >> On Jul 10, 2008, at 3:30 PM, J. Bruce Fields wrote: > >>> On Wed, Jul 09, 2008 at 08:37:24PM -0400, Chuck Lever wrote: > >>>> Introduce IPv6-enabled version of get_client_address. The legacy > >>>> mount > >>>> command could use this eventually as well. > >>>> > >>>> I don't remember how to tell an NFSv4 server to disable the callback > >>>> channel: whether an ANY address is passed with SETCLIENTID, or a > >>>> loopback address is passed. The patch allows either to be used with > >>>> a > >>>> compile-time switch. > >>> > >>> I would have thought INADDR_ANY. But in any case we should just pick > >>> one.... > >> > >> Well, yes, but we should pick the "correct" one. :-) The patch does it > >> this way just to make a note of this issue so we can make a decision > >> before committing this upstream. > >> > >> Does RFC 3530 have any recommendation about this? > > > > Not that I can find on a quick skim. > > Is it clarified in the NFSv4.1 draft? 4.1 callbacks use sessions, which I don't really know yet. > > I don't see why the spec would forbid running over loopback, though, in > > which case a loopback callback address would make sense. And I assume > > INADDR_ANY is always meaningless as a destination address, so is a > > logical way to tell the server it can't call back to you. > > Yep, I agree. > > I recall a few years back at a CITI bake-a-thon there was a certain > server vendor who had trouble with loopback callback addresses, > probably because their implementation was server-only, so an NFSv4 > callback from loopback would make no sense for them. The client in > this case was sending a loopback callback address because it hadn't > implemented a callback service and wanted to prevent the server from > calling it back. > > Do we have a high degree of certainty that sending an ANY address is > appropriate if the client can't determine a reasonable callback > address to send with SETCLIENTID? > > Is it at least OK for Linux's NFSv4 server? If not, it's a bug I'd want to fix. --b. > > If we think this might be a problem, I can change all this back to > simply failing the mount request when the mount.nfs command can't > figure out a valid callback address. > > >>>> > >>>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> > >>>> --- > >>>> > >>>> utils/mount/network.c | 122 +++++++++++++++++++++++++++++++++++++++ > >>>> ++++++++++ > >>>> utils/mount/network.h | 2 + > >>>> 2 files changed, 124 insertions(+), 0 deletions(-) > >>>> > >>>> diff --git a/utils/mount/network.c b/utils/mount/network.c > >>>> index 3f2721b..128d7f7 100644 > >>>> --- a/utils/mount/network.c > >>>> +++ b/utils/mount/network.c > >>>> @@ -918,3 +918,125 @@ 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, > >>>> +#ifdef GENERATE_LOOPBACK_ADDRESS > >>>> + .ai_flags = 0, /* loopback */ > >>>> +#else > >>>> + .ai_flags = AI_PASSIVE, /* ANYADDR */ > >>>> +#endif > >>>> + }; > >>>> + > >>>> + 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, > >>>> > > > > -- > Chuck Lever ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 04/14] text-based mount command: get_client_address support for IPv6 2008-07-11 19:06 ` J. Bruce Fields @ 2008-07-11 19:16 ` Chuck Lever 0 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-11 19:16 UTC (permalink / raw) To: J. Bruce Fields; +Cc: steved, linux-nfs On Fri, Jul 11, 2008 at 3:06 PM, J. Bruce Fields <bfields@fieldses.org> wrote: > On Thu, Jul 10, 2008 at 04:35:57PM -0400, Chuck Lever wrote: >> On Thu, Jul 10, 2008 at 3:43 PM, J. Bruce Fields <bfields@fieldses.org> wrote: >> > On Thu, Jul 10, 2008 at 03:36:21PM -0400, Chuck Lever wrote: >> >> On Jul 10, 2008, at 3:30 PM, J. Bruce Fields wrote: >> >>> On Wed, Jul 09, 2008 at 08:37:24PM -0400, Chuck Lever wrote: >> >>>> Introduce IPv6-enabled version of get_client_address. The legacy >> >>>> mount >> >>>> command could use this eventually as well. >> >>>> >> >>>> I don't remember how to tell an NFSv4 server to disable the callback >> >>>> channel: whether an ANY address is passed with SETCLIENTID, or a >> >>>> loopback address is passed. The patch allows either to be used with >> >>>> a >> >>>> compile-time switch. >> >>> >> >>> I would have thought INADDR_ANY. But in any case we should just pick >> >>> one.... >> >> >> >> Well, yes, but we should pick the "correct" one. :-) The patch does it >> >> this way just to make a note of this issue so we can make a decision >> >> before committing this upstream. >> >> >> >> Does RFC 3530 have any recommendation about this? >> > >> > Not that I can find on a quick skim. >> >> Is it clarified in the NFSv4.1 draft? > > 4.1 callbacks use sessions, which I don't really know yet. OK, but I thought the draft also contained some clarifications for 4.0, which is why I asked. Maybe I'm thinking of something else. >> > I don't see why the spec would forbid running over loopback, though, in >> > which case a loopback callback address would make sense. And I assume >> > INADDR_ANY is always meaningless as a destination address, so is a >> > logical way to tell the server it can't call back to you. >> >> Yep, I agree. >> >> I recall a few years back at a CITI bake-a-thon there was a certain >> server vendor who had trouble with loopback callback addresses, >> probably because their implementation was server-only, so an NFSv4 >> callback from loopback would make no sense for them. The client in >> this case was sending a loopback callback address because it hadn't >> implemented a callback service and wanted to prevent the server from >> calling it back. >> >> Do we have a high degree of certainty that sending an ANY address is >> appropriate if the client can't determine a reasonable callback >> address to send with SETCLIENTID? >> >> Is it at least OK for Linux's NFSv4 server? > > If not, it's a bug I'd want to fix. So to sum up, you think it is reasonable for the mount.nfs command to specify clientaddr=0.0.0.0 if it can't determine the client's own address for the server to use for callback. I can clean that up in these patches and repost. Thanks for the review. >> If we think this might be a problem, I can change all this back to >> simply failing the mount request when the mount.nfs command can't >> figure out a valid callback address. >> >> >>>> >> >>>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> >> >>>> --- >> >>>> >> >>>> utils/mount/network.c | 122 +++++++++++++++++++++++++++++++++++++++ >> >>>> ++++++++++ >> >>>> utils/mount/network.h | 2 + >> >>>> 2 files changed, 124 insertions(+), 0 deletions(-) >> >>>> >> >>>> diff --git a/utils/mount/network.c b/utils/mount/network.c >> >>>> index 3f2721b..128d7f7 100644 >> >>>> --- a/utils/mount/network.c >> >>>> +++ b/utils/mount/network.c >> >>>> @@ -918,3 +918,125 @@ 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, >> >>>> +#ifdef GENERATE_LOOPBACK_ADDRESS >> >>>> + .ai_flags = 0, /* loopback */ >> >>>> +#else >> >>>> + .ai_flags = AI_PASSIVE, /* ANYADDR */ >> >>>> +#endif >> >>>> + }; >> >>>> + >> >>>> + 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, >> >>>> >> >> >> >> -- >> Chuck Lever > -- Edward R. Murrow told his generation of journalists no one can eliminate their prejudices, just recognize them. Here is my bias: extremes of wealth and poverty cannot be reconciled with a truly just society. -- Bill Moyers ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 05/14] text-based mount command: Add helper to construct network addresses [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (3 preceding siblings ...) 2008-07-10 0:37 ` [PATCH 04/14] text-based mount command: get_client_address support for IPv6 Chuck Lever @ 2008-07-10 0:37 ` Chuck Lever 2008-07-10 0:37 ` [PATCH 06/14] text-based mount command: "addr=" option support for IPv6 addresses Chuck Lever ` (8 subsequent siblings) 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw) To: steved; +Cc: linux-nfs There are three helpers that convert sockaddr-style addresses to text addresses, then construct mount options to pass these addresses to the kernel. The tail of each of these helpers does exactly the same thing, so introduce a helper that handles the common code. Magically, the new helper supports IPv6 as well as IPv4. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/stropts.c | 31 +++++++++++++++++++++++++++++++ 1 files changed, 31 insertions(+), 0 deletions(-) diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index a9c0b50..a1ffca2 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -195,6 +195,37 @@ static time_t nfs_parse_retry_option(struct mount_options *options, } /* + * Convert the passed-in sockaddr-style address to presentation + * format, then append an option of the form "keyword=address". + * + * Returns 1 if the option was appended successfully; otherwise zero. + */ +static int nfs_append_generic_address_option(const struct sockaddr *sap, + const socklen_t salen, + const char *keyword, + struct mount_options *options) +{ + char address[NI_MAXHOST]; + char new_option[512]; + + if (!nfs_present_sockaddr(sap, salen, address, sizeof(address))) + goto out_err; + + if (snprintf(new_option, sizeof(new_option), "%s=%s", + keyword, address) >= sizeof(new_option)) + goto out_err; + + if (po_append(options, new_option) != PO_SUCCEEDED) + goto out_err; + + return 1; + +out_err: + nfs_error(_("%s: failed to construct %s option"), progname, keyword); + return 0; +} + +/* * Append the 'addr=' option to the options string to pass a resolved * server address to the kernel. After a successful mount, this address * is also added to /etc/mtab for use when unmounting. ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 06/14] text-based mount command: "addr=" option support for IPv6 addresses [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (4 preceding siblings ...) 2008-07-10 0:37 ` [PATCH 05/14] text-based mount command: Add helper to construct network addresses Chuck Lever @ 2008-07-10 0:37 ` Chuck Lever 2008-07-10 0:37 ` [PATCH 07/14] text-based mount command: "clientaddr=" " Chuck Lever ` (7 subsequent siblings) 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw) To: steved; +Cc: linux-nfs Change the append_addr_option() function to support sending either IPv4 or IPv6 addresses to the kernel via the "addr=" option. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/stropts.c | 21 ++++++--------------- 1 files changed, 6 insertions(+), 15 deletions(-) diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index a1ffca2..f856998 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -237,19 +237,12 @@ out_err: * Returns 1 if 'addr=' option appended successfully; * otherwise zero. */ -static int append_addr_option(struct sockaddr_in *saddr, - struct mount_options *options) +static int nfs_append_addr_option(const struct sockaddr *sap, + socklen_t salen, + struct mount_options *options) { - char new_option[24]; - po_remove_all(options, "addr"); - - snprintf(new_option, sizeof(new_option) - 1, - "addr=%s", inet_ntoa(saddr->sin_addr)); - - if (po_append(options, new_option) == PO_SUCCEEDED) - return 1; - return 0; + return nfs_append_generic_address_option(sap, salen, "addr", options); } /* @@ -358,10 +351,8 @@ static int nfs_validate_options(struct nfsmount_info *mi) if (!nfs_append_sloppy_option(mi->options)) return 0; - if (!append_addr_option(&saddr, mi->options)) - return 0; - - return 1; + return nfs_append_addr_option((struct sockaddr *)&saddr, + sizeof(saddr), mi->options); } /* ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 07/14] text-based mount command: "clientaddr=" option support for IPv6 addresses [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (5 preceding siblings ...) 2008-07-10 0:37 ` [PATCH 06/14] text-based mount command: "addr=" option support for IPv6 addresses Chuck Lever @ 2008-07-10 0:37 ` Chuck Lever 2008-07-10 0:37 ` [PATCH 08/14] text-based mount command: "mounthost=" " Chuck Lever ` (6 subsequent siblings) 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw) To: steved; +Cc: linux-nfs Change the append_clientaddr_option() function to support sending either IPv4 or IPv6 addresses to the kernel via the "clientaddr=" option. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/stropts.c | 26 ++++++++++++-------------- 1 files changed, 12 insertions(+), 14 deletions(-) diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index f856998..ff51652 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -252,24 +252,21 @@ static int nfs_append_addr_option(const struct sockaddr *sap, * Returns 1 if 'clientaddr=' option created successfully or if * 'clientaddr=' option is already present; otherwise zero. */ -static int append_clientaddr_option(struct sockaddr_in *saddr, - struct mount_options *options) +static int nfs_append_clientaddr_option(const struct sockaddr *sap, + socklen_t salen, + struct mount_options *options) { - struct sockaddr_in my_addr; - char new_option[32]; + struct sockaddr_storage dummy; + struct sockaddr *my_addr = (struct sockaddr *)&dummy; + socklen_t my_len = sizeof(dummy); - if (po_contains(options, "clientaddr") == PO_SUCCEEDED) + if (po_contains(options, "clientaddr") == PO_FOUND) return 1; - if (!get_client_address(saddr, &my_addr)) - return 0; - - snprintf(new_option, sizeof(new_option) - 1, - "clientaddr=%s", inet_ntoa(my_addr.sin_addr)); + nfs_callback_address(sap, salen, my_addr, &my_len); - if (po_append(options, new_option) == PO_SUCCEEDED) - return 1; - return 0; + return nfs_append_generic_address_option(my_addr, my_len, + "clientaddr", options); } /* @@ -339,7 +336,8 @@ static int nfs_validate_options(struct nfsmount_info *mi) return 0; if (strncmp(mi->type, "nfs4", 4) == 0) { - if (!append_clientaddr_option(&saddr, mi->options)) + if (!nfs_append_clientaddr_option((struct sockaddr *)&saddr, + sizeof(saddr), mi->options)) return 0; } else { if (!fix_mounthost_option(mi->options)) ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 08/14] text-based mount command: "mounthost=" option support for IPv6 addresses [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (6 preceding siblings ...) 2008-07-10 0:37 ` [PATCH 07/14] text-based mount command: "clientaddr=" " Chuck Lever @ 2008-07-10 0:37 ` Chuck Lever 2008-07-10 0:37 ` [PATCH 09/14] text-based mount command: Add IPv6 support to set_mandatory_options Chuck Lever ` (5 subsequent siblings) 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw) To: steved; +Cc: linux-nfs Change the fix_mounthost_option() function to support resolving IPv6 addresses. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/stropts.c | 33 +++++++++++++++++++++------------ 1 files changed, 21 insertions(+), 12 deletions(-) diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index ff51652..e2e72a7 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -94,6 +94,8 @@ struct nfsmount_info { int flags, /* MS_ flags */ fake, /* actually do the mount? */ child; /* forked bg child? */ + + sa_family_t family; /* supported address family */ }; static int nfs_parse_devname(struct nfsmount_info *mi) @@ -271,26 +273,28 @@ static int nfs_append_clientaddr_option(const struct sockaddr *sap, /* * Resolve the 'mounthost=' hostname and append a new option using - * the resulting IPv4 address. + * the resulting address. */ -static int fix_mounthost_option(struct mount_options *options) +static int nfs_fix_mounthost_option(const sa_family_t family, + struct mount_options *options) { - struct sockaddr_in maddr; - char *mounthost, new_option[32]; + struct sockaddr_storage dummy; + struct sockaddr *sap = (struct sockaddr *)&dummy; + socklen_t salen = sizeof(dummy); + char *mounthost; mounthost = po_get(options, "mounthost"); if (!mounthost) return 1; - if (!fill_ipv4_sockaddr(mounthost, &maddr)) + if (!nfs_name_to_address(mounthost, family, sap, &salen)) { + nfs_error(_("%s: unable to determine mount server's address"), + progname); return 0; + } - snprintf(new_option, sizeof(new_option) - 1, - "mountaddr=%s", inet_ntoa(maddr.sin_addr)); - - if (po_append(options, new_option) == PO_SUCCEEDED) - return 1; - return 0; + return nfs_append_generic_address_option(sap, salen, + "mountaddr", options); } /* @@ -340,7 +344,7 @@ static int nfs_validate_options(struct nfsmount_info *mi) sizeof(saddr), mi->options)) return 0; } else { - if (!fix_mounthost_option(mi->options)) + if (!nfs_fix_mounthost_option(mi->family, mi->options)) return 0; if (!mi->fake && !verify_lock_option(mi->options)) return 0; @@ -800,6 +804,11 @@ int nfsmount_string(const char *spec, const char *node, const char *type, .flags = flags, .fake = fake, .child = child, +#ifdef IPV6_SUPPORTED + .family = AF_UNSPEC, /* either IPv4 or v6 */ +#else + .family = AF_INET, /* only IPv4 */ +#endif }; int retval = EX_FAIL; ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 09/14] text-based mount command: Add IPv6 support to set_mandatory_options [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (7 preceding siblings ...) 2008-07-10 0:37 ` [PATCH 08/14] text-based mount command: "mounthost=" " Chuck Lever @ 2008-07-10 0:37 ` Chuck Lever 2008-07-10 0:37 ` [PATCH 10/14] text-based mount command: Support raw IPv6 address hostnames Chuck Lever ` (4 subsequent siblings) 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw) To: steved; +Cc: linux-nfs Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/stropts.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index e2e72a7..caa2c25 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -334,14 +334,15 @@ static int nfs_append_sloppy_option(struct mount_options *options) */ static int nfs_validate_options(struct nfsmount_info *mi) { - struct sockaddr_in saddr; + struct sockaddr_storage dummy; + struct sockaddr *sap = (struct sockaddr *)&dummy; + socklen_t salen = sizeof(dummy); - if (!fill_ipv4_sockaddr(mi->hostname, &saddr)) + if (!nfs_name_to_address(mi->hostname, mi->family, sap, &salen)) return 0; if (strncmp(mi->type, "nfs4", 4) == 0) { - if (!nfs_append_clientaddr_option((struct sockaddr *)&saddr, - sizeof(saddr), mi->options)) + if (!nfs_append_clientaddr_option(sap, salen, mi->options)) return 0; } else { if (!nfs_fix_mounthost_option(mi->family, mi->options)) @@ -353,8 +354,7 @@ static int nfs_validate_options(struct nfsmount_info *mi) if (!nfs_append_sloppy_option(mi->options)) return 0; - return nfs_append_addr_option((struct sockaddr *)&saddr, - sizeof(saddr), mi->options); + return nfs_append_addr_option(sap, salen, mi->options); } /* ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 10/14] text-based mount command: Support raw IPv6 address hostnames [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (8 preceding siblings ...) 2008-07-10 0:37 ` [PATCH 09/14] text-based mount command: Add IPv6 support to set_mandatory_options Chuck Lever @ 2008-07-10 0:37 ` Chuck Lever 2008-07-10 0:38 ` [PATCH 11/14] text-based mount command: Remove unused IPv4-only functions Chuck Lever ` (3 subsequent siblings) 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:37 UTC (permalink / raw) To: steved; +Cc: linux-nfs Traditionally the mount command has looked for a ":" to separate the server's hostname from the export path in the mounted on device name, like this: mount server:/export /mounted/on/dir The server's hostname is "server" and the export path is "/export". You can also substitute a specific IPv4 network address for the server hostname, like this: mount 192.168.0.55:/export /mounted/on/dir Raw IPv6 addresses present a problem, however, because they look something like this: fe80::200:5aff:fe00:30b Note the use of colons. To get around the presence of colons, copy the Solaris convention used for raw NFS server IPv6 addresses, which is to wrap the raw IPv6 address with square brackets. This is also suggested in RFC 4038. Introduce a new device name parser that can support traditional device names and square brackets. Place the parser in a separate source file so both the mount and umount paths can derive the server's hostname and export pathname the same way. Bonus points: add a check for NFS URLs and display an appropriate error message in that case. This is cleaner than failing with "unknown host: nfs". Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/Makefile.am | 6 + utils/mount/nfsumount.c | 35 +++---- utils/mount/parse_dev.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++ utils/mount/parse_dev.h | 28 ++++++ utils/mount/stropts.c | 59 +----------- 5 files changed, 282 insertions(+), 76 deletions(-) create mode 100644 utils/mount/parse_dev.c create mode 100644 utils/mount/parse_dev.h diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am index 5a94631..459fa45 100644 --- a/utils/mount/Makefile.am +++ b/utils/mount/Makefile.am @@ -9,10 +9,12 @@ man5_MANS = nfs.man sbin_PROGRAMS = mount.nfs EXTRA_DIST = nfsmount.x $(man8_MANS) $(man5_MANS) -mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c parse_opt.c \ +mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \ + parse_opt.c parse_dev.c \ nfsmount.c nfs4mount.c stropts.c\ nfsumount.c \ - mount_constants.h error.h network.h fstab.h token.h parse_opt.h \ + mount_constants.h error.h network.h fstab.h token.h \ + parse_opt.h parse_dev.h \ nfs4_mount.h nfs_mount4.h stropts.h version.h mount_nfs_LDADD = ../../support/nfs/libnfs.a \ diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c index 285273b..67e9c4b 100644 --- a/utils/mount/nfsumount.c +++ b/utils/mount/nfsumount.c @@ -34,6 +34,7 @@ #include "mount.h" #include "error.h" #include "network.h" +#include "parse_dev.h" #if !defined(MNT_FORCE) /* dare not try to include <linux/mount.h> -- lots of errors */ @@ -150,21 +151,11 @@ static int do_nfs_umount23(const char *spec, char *opts) struct mntent mnt = { .mnt_opts = opts }; struct pmap *pmap = &mnt_server.pmap; char *p; + int result = EX_USAGE; + + if (!nfs_parse_devname(spec, &hostname, &dirname)) + return result; - if (spec == NULL) { - nfs_error(_("%s: No NFS export name was provided"), - progname); - return EX_USAGE; - } - - p = strchr(spec, ':'); - if (p == NULL) { - nfs_error(_("%s: '%s' is not a legal NFS export name"), - progname, spec); - return EX_USAGE; - } - hostname = xstrndup(spec, p - spec); - dirname = xstrdup(p + 1); #ifdef NFS_MOUNT_DEBUG printf(_("host: %s, directory: %s\n"), hostname, dirname); #endif @@ -209,18 +200,24 @@ static int do_nfs_umount23(const char *spec, char *opts) pmap->pm_prot = IPPROTO_TCP; if (!nfs_gethostbyname(hostname, &mnt_server.saddr)) { - nfs_error(_("%s: '%s' does not contain a recognized hostname"), - progname, spec); - return EX_USAGE; + nfs_error(_("%s: DNS resolution of '%s' failed"), + progname, hostname); + goto out; } if (!nfs_call_umount(&mnt_server, &dirname)) { nfs_error(_("%s: Server failed to unmount '%s'"), progname, spec); - return EX_USAGE; + result = EX_FAIL; + goto out; } - return EX_SUCCESS; + result = EX_SUCCESS; + +out: + free(hostname); + free(dirname); + return result; } static struct option umount_longopts[] = diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c new file mode 100644 index 0000000..c0a8e18 --- /dev/null +++ b/utils/mount/parse_dev.c @@ -0,0 +1,230 @@ +/* + * parse_dev.c -- parse device name into hostname and export path + * + * Copyright (C) 2008 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "xcommon.h" +#include "nls.h" +#include "parse_dev.h" + +#ifndef NFS_MAXHOSTNAME +#define NFS_MAXHOSTNAME (255) +#endif + +#ifndef NFS_MAXPATHNAME +#define NFS_MAXPATHNAME (1024) +#endif + +extern char *progname; +extern int verbose; + +static int nfs_pdn_no_devname_err(void) +{ + nfs_error(_("%s: no device name was provided"), progname); + return 0; +} + +static int nfs_pdn_hostname_too_long_err(void) +{ + nfs_error(_("%s: server hostname is too long"), progname); + return 0; +} + +static int nfs_pdn_pathname_too_long_err(void) +{ + nfs_error(_("%s: export pathname is too long"), progname); + return 0; +} + +static int nfs_pdn_bad_format_err(void) +{ + nfs_error(_("%s: remote share not in 'host:dir' format"), progname); + return 0; +} + +static int nfs_pdn_nomem_err(void) +{ + nfs_error(_("%s: no memory available to parse devname"), progname); + return 0; +} + +static int nfs_pdn_missing_brace_err(void) +{ + nfs_error(_("%s: closing bracket missing from server address"), + progname); + return 0; +} + +/* + * Standard hostname:path format + */ +static int nfs_parse_simple_hostname(const char *dev, + char **hostname, char **pathname) +{ + size_t host_len, path_len; + char *colon, *comma; + + /* Must have a colon */ + colon = strchr(dev, ':'); + if (colon == NULL) + return nfs_pdn_bad_format_err(); + *colon = '\0'; + host_len = colon - dev; + + if (host_len > NFS_MAXHOSTNAME) + return nfs_pdn_hostname_too_long_err(); + + /* If there's a comma before the colon, take only the + * first name in list */ + comma = strchr(dev, ','); + if (comma != NULL) { + *comma = '\0'; + host_len = comma - dev; + nfs_error(_("%s: warning: multiple hostnames not supported"), + progname); + } else + + colon++; + path_len = strlen(colon); + if (path_len > NFS_MAXPATHNAME) + return nfs_pdn_pathname_too_long_err(); + + if (hostname) { + *hostname = strndup(dev, host_len); + if (*hostname == NULL) + return nfs_pdn_nomem_err(); + } + if (pathname) { + *pathname = strndup(colon, path_len); + if (*pathname == NULL) { + free(*hostname); + return nfs_pdn_nomem_err(); + } + } + return 1; +} + +/* + * To handle raw IPv6 addresses (which contain colons), the + * server's address is enclosed in square brackets. Return + * what's between the brackets. + * + * There could be anything in between the brackets, but we'll + * let DNS resolution sort it out later. + */ +static int nfs_parse_square_bracket(const char *dev, + char **hostname, char **pathname) +{ + size_t host_len, path_len; + char *cbrace; + + dev++; + + /* Must have a closing square bracket */ + cbrace = strchr(dev, ']'); + if (cbrace == NULL) + return nfs_pdn_missing_brace_err(); + *cbrace = '\0'; + host_len = cbrace - dev; + + /* Must have a colon just after the closing bracket */ + cbrace++; + if (*cbrace != ':') + return nfs_pdn_bad_format_err(); + + if (host_len > NFS_MAXHOSTNAME) + return nfs_pdn_hostname_too_long_err(); + + cbrace++; + path_len = strlen(cbrace); + if (path_len > NFS_MAXPATHNAME) + return nfs_pdn_pathname_too_long_err(); + + if (hostname) { + *hostname = strndup(dev, host_len); + if (*hostname == NULL) + return nfs_pdn_nomem_err(); + } + if (pathname) { + *pathname = strndup(cbrace, path_len); + if (*pathname == NULL) { + free(*hostname); + return nfs_pdn_nomem_err(); + } + } + return 1; +} + +/* + * RFC 2224 says an NFS client must grok "public file handles" to + * support NFS URLs. Linux doesn't do that yet. Print a somewhat + * helpful error message in this case instead of pressing forward + * with the mount request and failing with a cryptic error message + * later. + */ +static int nfs_parse_nfs_url(const char *dev, + char **hostname, char **pathname) +{ + nfs_error(_("%s: NFS URLs are not supported"), progname); + return 0; +} + +/** + * nfs_parse_devname - Determine the server's hostname by looking at "devname". + * @devname: pointer to mounted device name (first argument of mount command) + * @hostname: OUT: pointer to server's hostname + * @pathname: OUT: pointer to export path on server + * + * Returns 1 if succesful, or zero if some error occurred. On success, + * @hostname and @pathname point to dynamically allocated buffers containing + * the hostname of the server and the export pathname (both '\0'-terminated). + * + * @hostname or @pathname may be NULL if caller doesn't want a copy of those + * parts of @devname. + * + * Note that this will not work if @devname is a wide-character string. + */ +int nfs_parse_devname(const char *devname, + char **hostname, char **pathname) +{ + char *dev; + int result; + + if (devname == NULL) + return nfs_pdn_no_devname_err(); + + /* Parser is destructive, so operate on a copy of the device name. */ + dev = strdup(devname); + if (dev == NULL) + return nfs_pdn_nomem_err(); + if (*dev == '[') + result = nfs_parse_square_bracket(dev, hostname, pathname); + else if (strncmp(dev, "nfs://", 6) == 0) + result = nfs_parse_nfs_url(dev, hostname, pathname); + else + result = nfs_parse_simple_hostname(dev, hostname, pathname); + + free(dev); + return result; +} diff --git a/utils/mount/parse_dev.h b/utils/mount/parse_dev.h new file mode 100644 index 0000000..a1288c2 --- /dev/null +++ b/utils/mount/parse_dev.h @@ -0,0 +1,28 @@ +/* + * parse_dev.c -- parse device name into hostname and export path + * + * Copyright (C) 2008 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + * + */ + +#ifndef __NFS_UTILS_PARSE_DEV_HEADER +#define __NFS_UTILS_PARSE_DEV_HEADER + +extern int nfs_parse_devname(const char *, char **, char **); + +#endif /* __NFS_UTILS_PARSE_DEV */ diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index caa2c25..c4f2326 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -49,6 +49,7 @@ #include "network.h" #include "parse_opt.h" #include "version.h" +#include "parse_dev.h" #ifdef HAVE_RPCSVC_NFS_PROT_H #include <rpcsvc/nfs_prot.h> @@ -98,58 +99,6 @@ struct nfsmount_info { sa_family_t family; /* supported address family */ }; -static int nfs_parse_devname(struct nfsmount_info *mi) -{ - int ret = 0; - char *dev, *pathname, *s; - - dev = xstrdup(mi->spec); - - if (!(pathname = strchr(dev, ':'))) { - nfs_error(_("%s: remote share not in 'host:dir' format"), - progname); - goto out; - } - *pathname = '\0'; - pathname++; - - /* - * We don't need a copy of the pathname, but let's - * sanity check it anyway. - */ - if (strlen(pathname) > NFS_MAXPATHNAME) { - nfs_error(_("%s: export pathname is too long"), - progname); - goto out; - } - - /* - * Ignore all but first hostname in replicated mounts - * until they can be fully supported. (mack@sgi.com) - */ - if ((s = strchr(dev, ','))) { - *s = '\0'; - nfs_error(_("%s: warning: multiple hostnames not supported"), - progname); - nfs_error(_("%s: ignoring hostnames that follow the first one"), - progname); - } - mi->hostname = xstrdup(dev); - if (strlen(mi->hostname) > NFS_MAXHOSTNAME) { - nfs_error(_("%s: server hostname is too long"), - progname); - free(mi->hostname); - mi->hostname = NULL; - goto out; - } - - ret = 1; - -out: - free(dev); - return ret; -} - static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr) { struct hostent *hp; @@ -338,6 +287,9 @@ static int nfs_validate_options(struct nfsmount_info *mi) struct sockaddr *sap = (struct sockaddr *)&dummy; socklen_t salen = sizeof(dummy); + if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL)) + return 0; + if (!nfs_name_to_address(mi->hostname, mi->family, sap, &salen)) return 0; @@ -812,9 +764,6 @@ int nfsmount_string(const char *spec, const char *node, const char *type, }; int retval = EX_FAIL; - if (!nfs_parse_devname(&mi)) - return retval; - mi.options = po_split(*extra_opts); if (mi.options) { retval = nfsmount_start(&mi); ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 11/14] text-based mount command: Remove unused IPv4-only functions [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (9 preceding siblings ...) 2008-07-10 0:37 ` [PATCH 10/14] text-based mount command: Support raw IPv6 address hostnames Chuck Lever @ 2008-07-10 0:38 ` Chuck Lever 2008-07-10 0:38 ` [PATCH 12/14] text-based mount options: rename functions in stropts.c Chuck Lever ` (2 subsequent siblings) 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:38 UTC (permalink / raw) To: steved; +Cc: linux-nfs Clean up: remove unused IPv4-only functions used by the text-based mount command. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/network.c | 33 --------------------------------- utils/mount/network.h | 1 - utils/mount/stropts.c | 20 -------------------- 3 files changed, 0 insertions(+), 54 deletions(-) diff --git a/utils/mount/network.c b/utils/mount/network.c index 128d7f7..0c2bb23 100644 --- a/utils/mount/network.c +++ b/utils/mount/network.c @@ -886,39 +886,6 @@ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog, return 0; } -/** - * get_client_address - acquire our local network address - * @saddr: server's address - * @caddr: filled in with our network 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. - * - * Returns one if successful, otherwise zero. - */ -int get_client_address(struct sockaddr_in *saddr, struct sockaddr_in *caddr) -{ - socklen_t len = sizeof(*caddr); - int socket, err; - - socket = get_socket(saddr, IPPROTO_UDP, CONNECT_TIMEOUT, FALSE, TRUE); - if (socket == RPC_ANYSOCK) - return 0; - - err = getsockname(socket, caddr, &len); - close(socket); - - if (err && verbose) { - nfs_error(_("%s: getsockname failed: %s"), - progname, strerror(errno)); - return 0; - } - return 1; -} - /* * Try a getsockname() on a connected datagram socket. * diff --git a/utils/mount/network.h b/utils/mount/network.h index 2f4ff3a..544ac93 100644 --- a/utils/mount/network.h +++ b/utils/mount/network.h @@ -57,7 +57,6 @@ int nfs_string_to_sockaddr(const char *, const size_t, struct sockaddr *, socklen_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 *); diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index c4f2326..a51cf0b 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -99,26 +99,6 @@ struct nfsmount_info { sa_family_t family; /* supported address family */ }; -static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr) -{ - struct hostent *hp; - addr->sin_family = AF_INET; - - if (inet_aton(hostname, &addr->sin_addr)) - return 1; - if ((hp = gethostbyname(hostname)) == NULL) { - nfs_error(_("%s: can't get address for %s\n"), - progname, hostname); - return 0; - } - if (hp->h_length > sizeof(struct in_addr)) { - nfs_error(_("%s: got bad hp->h_length"), progname); - hp->h_length = sizeof(struct in_addr); - } - memcpy(&addr->sin_addr, hp->h_addr, hp->h_length); - return 1; -} - /* * Obtain a retry timeout value based on the value of the "retry=" option. * ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 12/14] text-based mount options: rename functions in stropts.c [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (10 preceding siblings ...) 2008-07-10 0:38 ` [PATCH 11/14] text-based mount command: Remove unused IPv4-only functions Chuck Lever @ 2008-07-10 0:38 ` Chuck Lever 2008-07-10 0:38 ` [PATCH 13/14] text-based mount command: remove unnecessary headers from stropts.c Chuck Lever 2008-07-10 0:38 ` [PATCH 14/14] mount command: Remove RPC headers from network.h Chuck Lever 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:38 UTC (permalink / raw) To: steved; +Cc: linux-nfs Clean up: rename a couple of functions in utils/mount/stropts.c to match the naming convention of the others. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/stropts.c | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index a51cf0b..b54df40 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -230,7 +230,7 @@ static int nfs_fix_mounthost_option(const sa_family_t family, * Returns zero if the "lock" option is in effect, but statd * can't be started. Otherwise, returns 1. */ -static int verify_lock_option(struct mount_options *options) +static int nfs_verify_lock_option(struct mount_options *options) { if (po_rightmost(options, "nolock", "lock") == PO_KEY1_RIGHTMOST) return 1; @@ -279,7 +279,7 @@ static int nfs_validate_options(struct nfsmount_info *mi) } else { if (!nfs_fix_mounthost_option(mi->family, mi->options)) return 0; - if (!mi->fake && !verify_lock_option(mi->options)) + if (!mi->fake && !nfs_verify_lock_option(mi->options)) return 0; } @@ -297,7 +297,7 @@ static int nfs_validate_options(struct nfsmount_info *mi) * passed-in error is permanent, thus the mount system call * should not be retried. */ -static int is_permanent_error(int error) +static int nfs_is_permanent_error(int error) { switch (error) { case ESTALE: @@ -316,13 +316,13 @@ static int is_permanent_error(int error) * * To handle version and transport protocol fallback properly, we * need to parse some of the mount options in order to set up a - * portmap probe. Mount options that rewrite_mount_options() + * portmap probe. Mount options that nfs_rewrite_mount_options() * doesn't recognize are left alone. * * Returns a new group of mount options if successful; otherwise * NULL is returned if some failure occurred. */ -static struct mount_options *rewrite_mount_options(char *str) +static struct mount_options *nfs_rewrite_mount_options(char *str) { struct mount_options *options; char *option, new_option[64]; @@ -475,7 +475,7 @@ static int nfs_retry_nfs23mount(struct nfsmount_info *mi) char *retry_str = NULL; char **extra_opts = mi->extra_opts; - retry_options = rewrite_mount_options(*extra_opts); + retry_options = nfs_rewrite_mount_options(*extra_opts); if (!retry_options) return 0; @@ -604,7 +604,7 @@ static int nfsmount_fg(struct nfsmount_info *mi) if (nfs_try_mount(mi)) return EX_SUCCESS; - if (is_permanent_error(errno)) + if (nfs_is_permanent_error(errno)) break; if (time(NULL) > timeout) { @@ -637,7 +637,7 @@ static int nfsmount_parent(struct nfsmount_info *mi) if (nfs_try_mount(mi)) return EX_SUCCESS; - if (is_permanent_error(errno)) { + if (nfs_is_permanent_error(errno)) { mount_error(mi->spec, mi->node, errno); return EX_FAIL; } @@ -672,7 +672,7 @@ static int nfsmount_child(struct nfsmount_info *mi) if (nfs_try_mount(mi)) return EX_SUCCESS; - if (is_permanent_error(errno)) + if (nfs_is_permanent_error(errno)) break; if (time(NULL) > timeout) ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 13/14] text-based mount command: remove unnecessary headers from stropts.c [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (11 preceding siblings ...) 2008-07-10 0:38 ` [PATCH 12/14] text-based mount options: rename functions in stropts.c Chuck Lever @ 2008-07-10 0:38 ` Chuck Lever 2008-07-10 0:38 ` [PATCH 14/14] mount command: Remove RPC headers from network.h Chuck Lever 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:38 UTC (permalink / raw) To: steved; +Cc: linux-nfs Clean up: remove unneeded headers from utils/mount/stropts.c. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/stropts.c | 14 +++----------- 1 files changed, 3 insertions(+), 11 deletions(-) diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index b54df40..e4a4408 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -25,11 +25,7 @@ #include <config.h> #endif -#include <ctype.h> #include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> #include <errno.h> #include <netdb.h> #include <time.h> @@ -42,7 +38,6 @@ #include "xcommon.h" #include "mount.h" #include "nls.h" -#include "nfs_mount.h" #include "mount_constants.h" #include "stropts.h" #include "error.h" @@ -51,15 +46,12 @@ #include "version.h" #include "parse_dev.h" -#ifdef HAVE_RPCSVC_NFS_PROT_H -#include <rpcsvc/nfs_prot.h> -#else -#include <linux/nfs.h> -#define nfsstat nfs_stat +#ifndef NFS_PROGRAM +#define NFS_PROGRAM (100003) #endif #ifndef NFS_PORT -#define NFS_PORT 2049 +#define NFS_PORT (2049) #endif #ifndef NFS_MAXHOSTNAME ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 14/14] mount command: Remove RPC headers from network.h [not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> ` (12 preceding siblings ...) 2008-07-10 0:38 ` [PATCH 13/14] text-based mount command: remove unnecessary headers from stropts.c Chuck Lever @ 2008-07-10 0:38 ` Chuck Lever 13 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-10 0:38 UTC (permalink / raw) To: steved; +Cc: linux-nfs Clean up: Include the bare minimum of legacy RPC headers in utils/mount/network.h. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- utils/mount/error.c | 2 -- utils/mount/mount.c | 1 - utils/mount/network.c | 11 ----------- utils/mount/network.h | 10 ---------- utils/mount/nfs4mount.c | 2 ++ utils/mount/nfsmount.c | 7 +++++++ 6 files changed, 9 insertions(+), 24 deletions(-) diff --git a/utils/mount/error.c b/utils/mount/error.c index 5fd5705..5c9d3f2 100644 --- a/utils/mount/error.c +++ b/utils/mount/error.c @@ -35,8 +35,6 @@ #include <fcntl.h> #include <syslog.h> #include <rpc/rpc.h> -#include <rpc/pmap_prot.h> -#include <rpc/pmap_clnt.h> #include "xcommon.h" #include "nls.h" diff --git a/utils/mount/mount.c b/utils/mount/mount.c index a7d5733..a806c7a 100644 --- a/utils/mount/mount.c +++ b/utils/mount/mount.c @@ -44,7 +44,6 @@ #include "nfs4_mount.h" #include "mount.h" #include "error.h" -#include "network.h" #include "stropts.h" #include "version.h" diff --git a/utils/mount/network.c b/utils/mount/network.c index 0c2bb23..fa8a361 100644 --- a/utils/mount/network.c +++ b/utils/mount/network.c @@ -48,17 +48,6 @@ #include "mount_constants.h" #include "network.h" -#ifdef HAVE_RPCSVC_NFS_PROT_H -#include <rpcsvc/nfs_prot.h> -#else -#include <linux/nfs.h> -#define nfsstat nfs_stat -#endif - -#ifndef NFS_PORT -#define NFS_PORT 2049 -#endif - #define PMAP_TIMEOUT (10) #define CONNECT_TIMEOUT (20) #define MOUNT_TIMEOUT (30) diff --git a/utils/mount/network.h b/utils/mount/network.h index 544ac93..a4dba1b 100644 --- a/utils/mount/network.h +++ b/utils/mount/network.h @@ -25,16 +25,6 @@ #define _NFS_UTILS_MOUNT_NETWORK_H #include <rpc/pmap_prot.h> -#include <rpc/clnt.h> - -#include "mount.h" - -#ifdef HAVE_RPCSVC_NFS_PROT_H -#include <rpcsvc/nfs_prot.h> -#else -#include <linux/nfs.h> -#define nfsstat nfs_stat -#endif #define MNT_SENDBUFSIZE (2048U) #define MNT_RECVBUFSIZE (1024U) diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c index 2b0fe2e..a2f318f 100644 --- a/utils/mount/nfs4mount.c +++ b/utils/mount/nfs4mount.c @@ -34,6 +34,7 @@ #include <arpa/inet.h> #include <rpc/auth.h> #include <rpc/rpc.h> + #ifdef HAVE_RPCSVC_NFS_PROT_H #include <rpcsvc/nfs_prot.h> #else @@ -45,6 +46,7 @@ #include "nls.h" #include "xcommon.h" +#include "mount.h" #include "mount_constants.h" #include "nfs4_mount.h" #include "nfs_mount.h" diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c index b343a1f..6355681 100644 --- a/utils/mount/nfsmount.c +++ b/utils/mount/nfsmount.c @@ -69,6 +69,13 @@ #include "network.h" #include "version.h" +#ifdef HAVE_RPCSVC_NFS_PROT_H +#include <rpcsvc/nfs_prot.h> +#else +#include <linux/nfs.h> +#define nfsstat nfs_stat +#endif + #ifndef NFS_PORT #define NFS_PORT 2049 #endif ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 00/14] Support for mounting NFSv4 servers over IPv6
@ 2008-07-11 20:34 Chuck Lever
[not found] ` <20080711203322.478.52095.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
0 siblings, 1 reply; 22+ messages in thread
From: Chuck Lever @ 2008-07-11 20:34 UTC (permalink / raw)
To: steved; +Cc: linux-nfs
Hi Steve-
Here is the latest version of the patches that add support to the text-
based mount.nfs command for mounting NFSv4 servers over IPv6. This set
replaces the set I sent a couple of days ago.
It was suggested that these be included in the next release of
nfs-utils, 1.1.3. Kernel support for these features (such as handling raw
IPv6 NFS server addresses properly when mounting) is planned for 2.6.27, so
inclusion of these patches would allow wider testing during .27's rc period.
Mounting NFSv2/v3 servers over IPv6 is more complex. It requires support
for a scalable rpcbind/portmap client built into nfs-utils, thus it is not
included in the present patch series. Anyone interested in looking at my
current prototype for this can check out:
http://git.linux-nfs.org/?p=cel/nfs-utils.git;a=summary
It includes all the patches in this series and the patches I posted last
week for nfs-utils 1.1.3, client-side support for NFSv2/v3 mounting and
unmounting over IPv6, a prototype IPv6-enabled sm-notify command, and
updates to nfs(5) describing IPv6 support for the NFS client.
For what it's worth, I'll be on holiday next week, but I can field any
questions or comments before this Saturday, or when I return.
---
Chuck Lever (14):
mount command: Remove RPC headers from network.h
text-based mount command: remove unnecessary headers from stropts.c
text-based mount options: rename functions in stropts.c
text-based mount command: Remove unused IPv4-only functions
text-based mount command: Support raw IPv6 address hostnames
text-based mount command: Add IPv6 support to set_mandatory_options
text-based mount command: "mounthost=" option support for IPv6 addresses
text-based mount command: "clientaddr=" option support for IPv6 addresses
text-based mount command: "addr=" option support for IPv6 addresses
text-based mount command: Add helper to construct network addresses
text-based mount command: get_client_address support for IPv6
mount command: Add functions to manage addresses in string form
text-based mount command: Add headers needed for IPv6 support
nfs-utils: Introduce new ./configure option: "--enable-ipv6"
configure.ac | 29 ++++++
utils/mount/Makefile.am | 6 +
utils/mount/error.c | 2
utils/mount/mount.c | 1
utils/mount/network.c | 237 +++++++++++++++++++++++++++++++++++++++++------
utils/mount/network.h | 17 +--
utils/mount/nfs4mount.c | 2
utils/mount/nfsmount.c | 7 +
utils/mount/nfsumount.c | 35 +++----
utils/mount/parse_dev.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++
utils/mount/parse_dev.h | 28 ++++++
utils/mount/stropts.c | 229 ++++++++++++++++++---------------------------
12 files changed, 617 insertions(+), 206 deletions(-)
create mode 100644 utils/mount/parse_dev.c
create mode 100644 utils/mount/parse_dev.h
--
Signature
--
corporate: <chuck dot lever at oracle dot com>
^ permalink raw reply [flat|nested] 22+ messages in thread[parent not found: <20080711203322.478.52095.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>]
* [PATCH 04/14] text-based mount command: get_client_address support for IPv6 [not found] ` <20080711203322.478.52095.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org> @ 2008-07-11 20:34 ` Chuck Lever 0 siblings, 0 replies; 22+ messages in thread From: Chuck Lever @ 2008-07-11 20:34 UTC (permalink / raw) To: steved; +Cc: linux-nfs 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, ^ permalink raw reply related [flat|nested] 22+ messages in thread
end of thread, other threads:[~2008-07-11 20:35 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-10 0:37 [PATCH 00/14] Support for mounting NFSv4 servers over IPv6 Chuck Lever
[not found] ` <20080710001725.6137.83845.stgit-lQeC5l55kZ7wdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-07-10 0:37 ` [PATCH 01/14] nfs-utils: Introduce new ./configure option: "--enable-ipv6" Chuck Lever
2008-07-10 0:37 ` [PATCH 02/14] text-based mount command: Add headers needed for IPv6 support Chuck Lever
2008-07-10 0:37 ` [PATCH 03/14] mount command: Add functions to manage addresses in string form Chuck Lever
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
2008-07-10 0:37 ` [PATCH 05/14] text-based mount command: Add helper to construct network addresses Chuck Lever
2008-07-10 0:37 ` [PATCH 06/14] text-based mount command: "addr=" option support for IPv6 addresses Chuck Lever
2008-07-10 0:37 ` [PATCH 07/14] text-based mount command: "clientaddr=" " Chuck Lever
2008-07-10 0:37 ` [PATCH 08/14] text-based mount command: "mounthost=" " Chuck Lever
2008-07-10 0:37 ` [PATCH 09/14] text-based mount command: Add IPv6 support to set_mandatory_options Chuck Lever
2008-07-10 0:37 ` [PATCH 10/14] text-based mount command: Support raw IPv6 address hostnames Chuck Lever
2008-07-10 0:38 ` [PATCH 11/14] text-based mount command: Remove unused IPv4-only functions Chuck Lever
2008-07-10 0:38 ` [PATCH 12/14] text-based mount options: rename functions in stropts.c Chuck Lever
2008-07-10 0:38 ` [PATCH 13/14] text-based mount command: remove unnecessary headers from stropts.c Chuck Lever
2008-07-10 0:38 ` [PATCH 14/14] mount command: Remove RPC headers from network.h Chuck Lever
-- strict thread matches above, loose matches on Subject: below --
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 04/14] text-based mount command: get_client_address support for IPv6 Chuck Lever
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox