diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2008-08-18 19:34:16 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2008-09-29 18:13:38 -0400 |
commit | a26cfad6e0a308a2c68df1f1ef50aabd48b17e6d (patch) | |
tree | 9d200a635720bde73b66fd96e4db9e7ff9be3af7 | |
parent | 7252d575ab0e8771269a3d245c36a05ace5152bd (diff) |
SUNRPC: Support IPv6 when registering kernel RPC services
In order to advertise NFS-related services on IPv6 interfaces via
rpcbind, the kernel RPC server implementation must use
rpcb_v4_register() instead of rpcb_register().
A new kernel build option allows distributions to use the legacy
v2 call until they integrate an appropriate user-space rpcbind
daemon that can support IPv6 RPC services.
I tried adding some automatic logic to fall back if registering
with a v4 protocol request failed, but there are too many corner
cases. So I just made it a compile-time switch that distributions
can throw when they've replaced portmapper with rpcbind.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r-- | fs/Kconfig | 22 | ||||
-rw-r--r-- | include/linux/sunrpc/svc.h | 4 | ||||
-rw-r--r-- | net/sunrpc/svc.c | 95 |
3 files changed, 113 insertions, 8 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index c6ae4d4842eb..ed57a5a37250 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -1773,6 +1773,28 @@ config SUNRPC_XPRT_RDMA | |||
1773 | 1773 | ||
1774 | If unsure, say N. | 1774 | If unsure, say N. |
1775 | 1775 | ||
1776 | config SUNRPC_REGISTER_V4 | ||
1777 | bool "Register local RPC services via rpcbind v4 (EXPERIMENTAL)" | ||
1778 | depends on SUNRPC && EXPERIMENTAL | ||
1779 | default n | ||
1780 | help | ||
1781 | Sun added support for registering RPC services at an IPv6 | ||
1782 | address by creating two new versions of the rpcbind protocol | ||
1783 | (RFC 1833). | ||
1784 | |||
1785 | This option enables support in the kernel RPC server for | ||
1786 | registering kernel RPC services via version 4 of the rpcbind | ||
1787 | protocol. If you enable this option, you must run a portmapper | ||
1788 | daemon that supports rpcbind protocol version 4. | ||
1789 | |||
1790 | Serving NFS over IPv6 from knfsd (the kernel's NFS server) | ||
1791 | requires that you enable this option and use a portmapper that | ||
1792 | supports rpcbind version 4. | ||
1793 | |||
1794 | If unsure, say N to get traditional behavior (register kernel | ||
1795 | RPC services using only rpcbind version 2). Distributions | ||
1796 | using the legacy Linux portmapper daemon must say N here. | ||
1797 | |||
1776 | config RPCSEC_GSS_KRB5 | 1798 | config RPCSEC_GSS_KRB5 |
1777 | tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)" | 1799 | tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)" |
1778 | depends on SUNRPC && EXPERIMENTAL | 1800 | depends on SUNRPC && EXPERIMENTAL |
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 23143f38b121..54a79e1ad634 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
@@ -393,7 +393,9 @@ struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, | |||
393 | int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); | 393 | int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); |
394 | void svc_destroy(struct svc_serv *); | 394 | void svc_destroy(struct svc_serv *); |
395 | int svc_process(struct svc_rqst *); | 395 | int svc_process(struct svc_rqst *); |
396 | int svc_register(struct svc_serv *, int, unsigned short); | 396 | int svc_register(const struct svc_serv *, const unsigned short, |
397 | const unsigned short); | ||
398 | |||
397 | void svc_wake_up(struct svc_serv *); | 399 | void svc_wake_up(struct svc_serv *); |
398 | void svc_reserve(struct svc_rqst *rqstp, int space); | 400 | void svc_reserve(struct svc_rqst *rqstp, int space); |
399 | struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu); | 401 | struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu); |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 9eb78a771da5..c43ccb628052 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -719,13 +719,92 @@ svc_exit_thread(struct svc_rqst *rqstp) | |||
719 | } | 719 | } |
720 | EXPORT_SYMBOL(svc_exit_thread); | 720 | EXPORT_SYMBOL(svc_exit_thread); |
721 | 721 | ||
722 | #ifdef CONFIG_SUNRPC_REGISTER_V4 | ||
722 | /* | 723 | /* |
723 | * Register an RPC service with the local portmapper. | 724 | * Registering kernel RPC services with rpcbind version 2 will work |
724 | * To unregister a service, call this routine with | 725 | * over either IPv4 or IPv6, since the Linux kernel always registers |
725 | * proto and port == 0. | 726 | * services for the "any" address. |
727 | * | ||
728 | * However, the local rpcbind daemon listens on either only AF_INET | ||
729 | * or AF_INET6 (never both). When it listens on AF_INET6, an rpcbind | ||
730 | * version 2 registration will result in registering the service at | ||
731 | * IN6ADDR_ANY, even if the RPC service being registered is not | ||
732 | * IPv6-enabled. | ||
733 | * | ||
734 | * Rpcbind version 4 allows us to be a little more specific. Kernel | ||
735 | * RPC services that don't yet support AF_INET6 can register | ||
736 | * themselves as IPv4-only with the local rpcbind daemon, even if the | ||
737 | * daemon is listening only on AF_INET6. | ||
738 | * | ||
739 | * And, registering IPv6-enabled kernel RPC services via AF_INET6 | ||
740 | * verifies that the local user space rpcbind daemon is properly | ||
741 | * configured to support remote AF_INET6 rpcbind requests. | ||
742 | * | ||
743 | * An AF_INET6 registration request will fail if the local rpcbind | ||
744 | * daemon is not set up to listen on AF_INET6. Likewise, we fail | ||
745 | * AF_INET6 registration requests if svc_register() is configured to | ||
746 | * support only rpcbind version 2. | ||
726 | */ | 747 | */ |
727 | int | 748 | static int __svc_register(const u32 program, const u32 version, |
728 | svc_register(struct svc_serv *serv, int proto, unsigned short port) | 749 | const sa_family_t family, |
750 | const unsigned short protocol, | ||
751 | const unsigned short port) | ||
752 | { | ||
753 | struct sockaddr_in sin = { | ||
754 | .sin_family = AF_INET, | ||
755 | .sin_addr.s_addr = htonl(INADDR_ANY), | ||
756 | .sin_port = htons(port), | ||
757 | }; | ||
758 | struct sockaddr_in6 sin6 = { | ||
759 | .sin6_family = AF_INET6, | ||
760 | .sin6_addr = IN6ADDR_ANY_INIT, | ||
761 | .sin6_port = htons(port), | ||
762 | }; | ||
763 | struct sockaddr *sap; | ||
764 | char *netid; | ||
765 | |||
766 | switch (family) { | ||
767 | case AF_INET: | ||
768 | sap = (struct sockaddr *)&sin; | ||
769 | netid = RPCBIND_NETID_TCP; | ||
770 | if (protocol == IPPROTO_UDP) | ||
771 | netid = RPCBIND_NETID_UDP; | ||
772 | break; | ||
773 | case AF_INET6: | ||
774 | sap = (struct sockaddr *)&sin6; | ||
775 | netid = RPCBIND_NETID_TCP6; | ||
776 | if (protocol == IPPROTO_UDP) | ||
777 | netid = RPCBIND_NETID_UDP6; | ||
778 | break; | ||
779 | default: | ||
780 | return -EAFNOSUPPORT; | ||
781 | } | ||
782 | |||
783 | return rpcb_v4_register(program, version, sap, netid); | ||
784 | } | ||
785 | #else | ||
786 | static int __svc_register(const u32 program, const u32 version, | ||
787 | sa_family_t family, | ||
788 | const unsigned short protocol, | ||
789 | const unsigned short port) | ||
790 | { | ||
791 | if (family != AF_INET) | ||
792 | return -EAFNOSUPPORT; | ||
793 | |||
794 | return rpcb_register(program, version, protocol, port); | ||
795 | } | ||
796 | #endif | ||
797 | |||
798 | /** | ||
799 | * svc_register - register an RPC service with the local portmapper | ||
800 | * @serv: svc_serv struct for the service to register | ||
801 | * @proto: transport protocol number to advertise | ||
802 | * @port: port to advertise | ||
803 | * | ||
804 | * Service is registered for any address in serv's address family | ||
805 | */ | ||
806 | int svc_register(const struct svc_serv *serv, const unsigned short proto, | ||
807 | const unsigned short port) | ||
729 | { | 808 | { |
730 | struct svc_program *progp; | 809 | struct svc_program *progp; |
731 | unsigned int i; | 810 | unsigned int i; |
@@ -738,8 +817,9 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port) | |||
738 | if (progp->pg_vers[i] == NULL) | 817 | if (progp->pg_vers[i] == NULL) |
739 | continue; | 818 | continue; |
740 | 819 | ||
741 | dprintk("svc: svc_register(%s, %s, %d, %d)%s\n", | 820 | dprintk("svc: svc_register(%s, %u, %s, %u, %d)%s\n", |
742 | progp->pg_name, | 821 | progp->pg_name, |
822 | serv->sv_family, | ||
743 | proto == IPPROTO_UDP? "udp" : "tcp", | 823 | proto == IPPROTO_UDP? "udp" : "tcp", |
744 | port, | 824 | port, |
745 | i, | 825 | i, |
@@ -749,7 +829,8 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port) | |||
749 | if (progp->pg_vers[i]->vs_hidden) | 829 | if (progp->pg_vers[i]->vs_hidden) |
750 | continue; | 830 | continue; |
751 | 831 | ||
752 | error = rpcb_register(progp->pg_prog, i, proto, port); | 832 | error = __svc_register(progp->pg_prog, i, |
833 | serv->sv_family, proto, port); | ||
753 | if (error < 0) | 834 | if (error < 0) |
754 | break; | 835 | break; |
755 | } | 836 | } |