public inbox for linux-nfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] nfs-utils: add IPv6 support to rpc.nfsd (RFC)
@ 2009-05-11 17:58 Jeff Layton
  2009-05-11 17:58 ` [PATCH 1/3] nfs-utils: rearrange nfssvc.c Jeff Layton
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Jeff Layton @ 2009-05-11 17:58 UTC (permalink / raw)
  To: linux-nfs; +Cc: chuck.lever

This patchset is a first pass at adding IPv6 support to rpc.nfsd.

With the existing code on a relatively recent kernel with nfsdfs
mounted, rpc.nfsd will create IPv4 sockets and hand them off to the
kernel. The idea with this patchset is to have it do the same thing for
IPv6 sockets.

The kernel code for nfsd IPv6 support is not yet in place, so this code
isn't really very useful yet. I've tested this though against a patchset
from Chuck Lever's tree and seems to do the right thing there.

I've also done a bit of testing with this new code on existing kernels
and it seems to still work correctly.

It also optimizes the knfsd shutdown case a bit -- when setting the
threads to 0, the current code still opens sockets and hands them off to
the kernel, even though they'll never actually be used.

This patchset is just an RFC at the moment. The code is usable and
shouldn't break anything, but I'd like to see the kernel interfaces for
this in place before we commit this to the repo. It might be useful for
people working on IPv6 support for knfsd however.

Comments and suggestions appreciated.

Jeff Layton (3):
  nfs-utils: rearrange nfssvc.c
  nfs-utils: set IPV6_V6ONLY on nfssvc IPv6 sockets
  nfs-utils: add IPv6 support to nfsd

 support/include/nfslib.h |    5 +-
 support/nfs/nfssvc.c     |   91 ++++++++++++++++++-----------
 utils/nfsd/nfsd.c        |  142 ++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 178 insertions(+), 60 deletions(-)


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/3] nfs-utils: rearrange nfssvc.c
  2009-05-11 17:58 [PATCH 0/3] nfs-utils: add IPv6 support to rpc.nfsd (RFC) Jeff Layton
@ 2009-05-11 17:58 ` Jeff Layton
  2009-05-11 17:58 ` [PATCH 2/3] nfs-utils: set IPV6_V6ONLY on nfssvc IPv6 sockets Jeff Layton
  2009-05-11 17:58 ` [PATCH 3/3] nfs-utils: add IPv6 support to nfsd Jeff Layton
  2 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2009-05-11 17:58 UTC (permalink / raw)
  To: linux-nfs; +Cc: chuck.lever

nfssvc.c contains functions for starting up knfsd. Currently, the only
non-static function in that file is nfssvc(). In order to add IPv6
support, we'll need to be able to call some of these functions in a
more granular fashion.

Reorganize these functions and add prototypes to the header so that
they can be called individually, and change the nfsd program to call
those routines individually.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 support/include/nfslib.h |    5 +++-
 support/nfs/nfssvc.c     |   65 ++++++++++++++++++++++++---------------------
 utils/nfsd/nfsd.c        |   17 +++++++++++-
 3 files changed, 55 insertions(+), 32 deletions(-)

diff --git a/support/include/nfslib.h b/support/include/nfslib.h
index 9d0d39d..30baa85 100644
--- a/support/include/nfslib.h
+++ b/support/include/nfslib.h
@@ -130,7 +130,10 @@ int			wildmat(char *text, char *pattern);
  * nfsd library functions.
  */
 int			nfsctl(int, struct nfsctl_arg *, union nfsctl_res *);
-int			nfssvc(int port, int nrservs, unsigned int versbits, unsigned int portbits, char *haddr);
+void			nfssvc_setfds(unsigned int ctlbits, struct sockaddr *sa,
+					socklen_t addrlen);
+void			nfssvc_setvers(unsigned int ctlbits);
+int			nfssvc_threads(unsigned short port, int nrservs);
 int			nfsaddclient(struct nfsctl_client *clp);
 int			nfsdelclient(struct nfsctl_client *clp);
 int			nfsexport(struct nfsctl_export *exp);
diff --git a/support/nfs/nfssvc.c b/support/nfs/nfssvc.c
index 9bbc9a5..c9b09dd 100644
--- a/support/nfs/nfssvc.c
+++ b/support/nfs/nfssvc.c
@@ -25,34 +25,45 @@
 #define NFSD_VERS_FILE    "/proc/fs/nfsd/versions"
 #define NFSD_THREAD_FILE  "/proc/fs/nfsd/threads"
 
-static void
-nfssvc_setfds(int port, unsigned int ctlbits, char *haddr)
+/*
+ * Are there already sockets configured? If not, then it is safe to try to
+ * open some and pass them through.
+ *
+ * Note: If the user explicitly asked for 'udp', then we should probably check
+ * if that is open, and should open it if not.  However we don't yet. All
+ * sockets * have to be opened when the first daemon is started.
+ */
+int
+nfssvc_inuse()
 {
-	int fd, n, on=1;
+	int fd, n;
 	char buf[BUFSIZ];
-	int udpfd = -1, tcpfd = -1;
-	struct sockaddr_in sin;
 
 	fd = open(NFSD_PORTS_FILE, O_RDONLY);
+
+	/* problem opening file, assume that nothing is configured */
 	if (fd < 0)
-		return;
+		return 0;
+
 	n = read(fd, buf, BUFSIZ);
 	close(fd);
+
 	if (n != 0)
-		return;
-	/* there are no ports currently open, so it is safe to
-	 * try to open some and pass them through.
-	 * Note: If the user explicitly asked for 'udp', then
-	 * we should probably check if that is open, and should
-	 * open it if not.  However we don't yet.  All sockets
-	 * have to be opened when the first daemon is started.
-	 */
+		return 1;
+
+	return 0;
+}
+
+void
+nfssvc_setfds(unsigned int ctlbits, struct sockaddr *sa, socklen_t addrlen)
+{
+	int fd, on = 1;
+	char buf[BUFSIZ];
+	int udpfd = -1, tcpfd = -1;
+
 	fd = open(NFSD_PORTS_FILE, O_WRONLY);
 	if (fd < 0)
 		return;
-	sin.sin_family = AF_INET;
-	sin.sin_port   = htons(port);
-	sin.sin_addr.s_addr =  inet_addr(haddr);
 
 	if (NFSCTL_UDPISSET(ctlbits)) {
 		udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
@@ -61,7 +72,7 @@ nfssvc_setfds(int port, unsigned int ctlbits, char *haddr)
 				"errno %d (%s)\n", errno, strerror(errno));
 			exit(1);
 		}
-		if (bind(udpfd, (struct  sockaddr  *)&sin, sizeof(sin)) < 0){
+		if (bind(udpfd, sa, addrlen) < 0) {
 			syslog(LOG_ERR, "nfssvc: unable to bind UPD socket: "
 				"errno %d (%s)\n", errno, strerror(errno));
 			exit(1);
@@ -80,7 +91,7 @@ nfssvc_setfds(int port, unsigned int ctlbits, char *haddr)
 				"errno %d (%s)\n", errno, strerror(errno));
 			exit(1);
 		}
-		if (bind(tcpfd, (struct  sockaddr  *)&sin, sizeof(sin)) < 0){
+		if (bind(tcpfd, sa, addrlen) < 0) {
 			syslog(LOG_ERR, "nfssvc: unable to bind TCP socket: "
 				"errno %d (%s)\n", errno, strerror(errno));
 			exit(1);
@@ -115,8 +126,9 @@ nfssvc_setfds(int port, unsigned int ctlbits, char *haddr)
 
 	return;
 }
-static void
-nfssvc_versbits(unsigned int ctlbits)
+
+void
+nfssvc_setvers(unsigned int ctlbits)
 {
 	int fd, n, off;
 	char buf[BUFSIZ], *ptr;
@@ -142,20 +154,13 @@ nfssvc_versbits(unsigned int ctlbits)
 
 	return;
 }
+
 int
-nfssvc(int port, int nrservs, unsigned int versbits, unsigned protobits,
-	char *haddr)
+nfssvc_threads(unsigned short port, int nrservs)
 {
 	struct nfsctl_arg	arg;
 	int fd;
 
-	/* Note: must set versions before fds so that
-	 * the ports get registered with portmap against correct
-	 * versions
-	 */
-	nfssvc_versbits(versbits);
-	nfssvc_setfds(port, protobits, haddr);
-
 	fd = open(NFSD_THREAD_FILE, O_WRONLY);
 	if (fd < 0)
 		fd = open("/proc/fs/nfs/threads", O_WRONLY);
diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
index c97c81f..25babe1 100644
--- a/utils/nfsd/nfsd.c
+++ b/utils/nfsd/nfsd.c
@@ -49,6 +49,7 @@ main(int argc, char **argv)
 	int	count = 1, c, error, port, fd, found_one;
 	struct servent *ent;
 	struct hostent *hp;
+	struct sockaddr_in sin;
 
 	ent = getservbyname ("nfs", "udp");
 	if (ent != NULL)
@@ -157,8 +158,22 @@ main(int argc, char **argv)
 	}
 	closeall(3);
 
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(port);
+	sin.sin_addr.s_addr = inet_addr(haddr);
+
+	/*
+	 * must set versions before the fd's so that the right versions get
+	 * registered with rpcbind. Note that on older kernels w/o the right
+	 * interfaces, these are a no-op.
+	 */
+	if (!nfssvc_inuse()) {
+		nfssvc_setvers(versbits);
+		nfssvc_setfds(protobits, (struct sockaddr *) &sin, sizeof(sin));
+	}
+
 	openlog("nfsd", LOG_PID, LOG_DAEMON);
-	if ((error = nfssvc(port, count, versbits, protobits, haddr)) < 0) {
+	if ((error = nfssvc_threads(port, count)) < 0) {
 		int e = errno;
 		syslog(LOG_ERR, "nfssvc: %s", strerror(e));
 		closelog();
-- 
1.6.0.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/3] nfs-utils: set IPV6_V6ONLY on nfssvc IPv6 sockets
  2009-05-11 17:58 [PATCH 0/3] nfs-utils: add IPv6 support to rpc.nfsd (RFC) Jeff Layton
  2009-05-11 17:58 ` [PATCH 1/3] nfs-utils: rearrange nfssvc.c Jeff Layton
@ 2009-05-11 17:58 ` Jeff Layton
  2009-05-11 17:58 ` [PATCH 3/3] nfs-utils: add IPv6 support to nfsd Jeff Layton
  2 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2009-05-11 17:58 UTC (permalink / raw)
  To: linux-nfs; +Cc: chuck.lever

IPv6 sockets for knfsd can't be allowed to accept IPv4 packets. Set the
correct option to prevent it.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 support/nfs/nfssvc.c |   26 +++++++++++++++++++++-----
 1 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/support/nfs/nfssvc.c b/support/nfs/nfssvc.c
index c9b09dd..914bb3f 100644
--- a/support/nfs/nfssvc.c
+++ b/support/nfs/nfssvc.c
@@ -60,29 +60,37 @@ nfssvc_setfds(unsigned int ctlbits, struct sockaddr *sa, socklen_t addrlen)
 	int fd, on = 1;
 	char buf[BUFSIZ];
 	int udpfd = -1, tcpfd = -1;
+	unsigned short family = sa->sa_family;
 
 	fd = open(NFSD_PORTS_FILE, O_WRONLY);
 	if (fd < 0)
 		return;
 
 	if (NFSCTL_UDPISSET(ctlbits)) {
-		udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+		udpfd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
 		if (udpfd < 0) {
-			syslog(LOG_ERR, "nfssvc: unable to create UPD socket: "
+			syslog(LOG_ERR, "nfssvc: unable to create UDP socket: "
+				"errno %d (%s)\n", errno, strerror(errno));
+			exit(1);
+		}
+		if (family == AF_INET6 && setsockopt(udpfd, IPPROTO_IPV6,
+						     IPV6_V6ONLY, &on,
+						     sizeof(on))) {
+			syslog(LOG_ERR, "nfssvc: unable to set IPV6_V6ONLY: "
 				"errno %d (%s)\n", errno, strerror(errno));
 			exit(1);
 		}
 		if (bind(udpfd, sa, addrlen) < 0) {
-			syslog(LOG_ERR, "nfssvc: unable to bind UPD socket: "
+			syslog(LOG_ERR, "nfssvc: unable to bind UDP socket: "
 				"errno %d (%s)\n", errno, strerror(errno));
 			exit(1);
 		}
 	}
 
 	if (NFSCTL_TCPISSET(ctlbits)) {
-		tcpfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+		tcpfd = socket(family, SOCK_STREAM, IPPROTO_TCP);
 		if (tcpfd < 0) {
-			syslog(LOG_ERR, "nfssvc: unable to createt tcp socket: "
+			syslog(LOG_ERR, "nfssvc: unable to createt TCP socket: "
 				"errno %d (%s)\n", errno, strerror(errno));
 			exit(1);
 		}
@@ -91,6 +99,14 @@ nfssvc_setfds(unsigned int ctlbits, struct sockaddr *sa, socklen_t addrlen)
 				"errno %d (%s)\n", errno, strerror(errno));
 			exit(1);
 		}
+		if (family == AF_INET6 && setsockopt(tcpfd, IPPROTO_IPV6,
+						     IPV6_V6ONLY, &on,
+						     sizeof(on))) {
+			syslog(LOG_ERR, "nfssvc: unable to set IPV6_V6ONLY: "
+				"errno %d (%s)\n", errno, strerror(errno));
+			exit(1);
+		}
+
 		if (bind(tcpfd, sa, addrlen) < 0) {
 			syslog(LOG_ERR, "nfssvc: unable to bind TCP socket: "
 				"errno %d (%s)\n", errno, strerror(errno));
-- 
1.6.0.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/3] nfs-utils: add IPv6 support to nfsd
  2009-05-11 17:58 [PATCH 0/3] nfs-utils: add IPv6 support to rpc.nfsd (RFC) Jeff Layton
  2009-05-11 17:58 ` [PATCH 1/3] nfs-utils: rearrange nfssvc.c Jeff Layton
  2009-05-11 17:58 ` [PATCH 2/3] nfs-utils: set IPV6_V6ONLY on nfssvc IPv6 sockets Jeff Layton
@ 2009-05-11 17:58 ` Jeff Layton
  2009-05-11 19:34   ` Chuck Lever
  2 siblings, 1 reply; 7+ messages in thread
From: Jeff Layton @ 2009-05-11 17:58 UTC (permalink / raw)
  To: linux-nfs; +Cc: chuck.lever

Add 2 new options to rpc.nfsd -- -4 and -6. -4 makes it an IPv4-only
server, and -6 makes it IPv6-only. Restructure the -H option so that
if the address appears to be or resolves to an IPv4 address, that
IPv6 is disabled. Ditto if it resolves to an IPv6 address.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 utils/nfsd/nfsd.c |  137 +++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 108 insertions(+), 29 deletions(-)

diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
index 25babe1..0022e65 100644
--- a/utils/nfsd/nfsd.c
+++ b/utils/nfsd/nfsd.c
@@ -41,7 +41,6 @@ static struct option longopts[] =
 };
 unsigned int protobits = NFSCTL_ALLBITS;
 unsigned int versbits = NFSCTL_ALLBITS;
-char *haddr = NULL;
 
 int
 main(int argc, char **argv)
@@ -49,7 +48,15 @@ main(int argc, char **argv)
 	int	count = 1, c, error, port, fd, found_one;
 	struct servent *ent;
 	struct hostent *hp;
-	struct sockaddr_in sin;
+	struct sockaddr_in sin = { };
+	struct sockaddr_in6 sin6 = { };
+	char	*haddr = NULL;
+	int	ipv4 = 1;
+#ifdef IPV6_SUPPORTED
+	int	ipv6 = 1;
+#else  /* IPV6_SUPPORTED */
+	int	ipv6 = 0;
+#endif /* IPV6_SUPPORTED */
 
 	ent = getservbyname ("nfs", "udp");
 	if (ent != NULL)
@@ -57,18 +64,12 @@ main(int argc, char **argv)
 	else
 		port = 2049;
 
-	while ((c = getopt_long(argc, argv, "H:hN:p:P:TU", longopts, NULL)) != EOF) {
+	while ((c = getopt_long(argc, argv, "H:hN:p:P:TU46", longopts, NULL)) != EOF) {
 		switch(c) {
 		case 'H':
-			if (inet_addr(optarg) != INADDR_NONE) {
-				haddr = strdup(optarg);
-			} else if ((hp = gethostbyname(optarg)) != NULL) {
-				haddr = inet_ntoa((*(struct in_addr*)(hp->h_addr_list[0])));
-			} else {
-				fprintf(stderr, "%s: Unknown hostname: %s\n",
-					argv[0], optarg);
-				usage(argv [0]);
-			}
+			/* we only deal with one host addr at the moment */
+			free(haddr);
+			haddr = strdup(optarg);
 			break;
 		case 'P':	/* XXX for nfs-server compatibility */
 		case 'p':
@@ -92,24 +93,76 @@ main(int argc, char **argv)
 			}
 			break;
 		case 'T':
-				NFSCTL_TCPUNSET(protobits);
-				break;
+			NFSCTL_TCPUNSET(protobits);
+			break;
 		case 'U':
-				NFSCTL_UDPUNSET(protobits);
-				break;
+			NFSCTL_UDPUNSET(protobits);
+			break;
+		case '4':
+			ipv6 = 0;
+			break;
+		case '6':
+			ipv4 = 0;
+			break;
 		default:
 			fprintf(stderr, "Invalid argument: '%c'\n", c);
 		case 'h':
 			usage(argv[0]);
 		}
 	}
-	/*
-	 * Do some sanity checking, if the ctlbits are set
-	 */
+
+	/* sanity checks */
+
+	/* if an address was specified, check it first */
+	if (haddr) {
+		/* does it look like an addr of some sort? */
+		if (inet_pton(AF_INET, haddr, &sin.sin_addr)) {
+			ipv6 = 0;
+			goto family_check;
+		} else if (inet_pton(AF_INET6, haddr, &sin6.sin6_addr)) {
+			ipv4 = 0;
+			goto family_check;
+		}
+
+		/* see if it's a hostname */
+		hp = gethostbyname(haddr);
+		if (!hp) {
+			fprintf(stderr, "%s: gethostbyname on %s failed: %d\n",
+					argv[0], haddr, h_errno);
+			error = h_errno;
+			usage(argv[0]);
+		}
+
+		if (hp->h_addrtype == AF_INET) {
+			ipv6 = 0;
+			memcpy(&sin.sin_addr, hp->h_addr_list[0],
+			       hp->h_length);
+			if (sin.sin_addr == INADDR_NONE) {
+				fprintf(stderr, "%s: Bad hostaddr %s\n",
+						argv[0], haddr);
+				usage(argv[0]);
+			}
+		} else if (hp->h_addrtype == AF_INET6) {
+			ipv4 = 0;
+			memcpy(&sin6.sin6_addr, hp->h_addr_list[0],
+			       hp->h_length);
+		}
+	}
+
+family_check:
+	/* make sure at least one address family is enabled */
+	if (!ipv4 && !ipv6) {
+		fprintf(stderr, "no address families enabled\n");
+		exit(1);
+	}
+
+	/* make sure at least one protocol type is enabled */
 	if (!NFSCTL_UDPISSET(protobits) && !NFSCTL_TCPISSET(protobits)) {
 		fprintf(stderr, "invalid protocol specified\n");
 		exit(1);
 	}
+
+	/* make sure that at least one version is enabled */
 	found_one = 0;
 	for (c = NFSD_MINVERS; c <= NFSD_MAXVERS; c++) {
 		if (NFSCTL_VERISSET(versbits, c))
@@ -120,14 +173,11 @@ main(int argc, char **argv)
 		exit(1);
 	}			
 
+	/* must have TCP for NFSv4 */
 	if (NFSCTL_VERISSET(versbits, 4) && !NFSCTL_TCPISSET(protobits)) {
 		fprintf(stderr, "version 4 requires the TCP protocol\n");
 		exit(1);
 	}
-	if (haddr == NULL) {
-		struct in_addr in = {INADDR_ANY}; 
-		haddr = strdup(inet_ntoa(in));
-	}
 
 	if (chdir(NFS_STATEDIR)) {
 		fprintf(stderr, "%s: chdir(%s) failed: %s\n",
@@ -142,6 +192,12 @@ main(int argc, char **argv)
 				"%s: invalid server count (%d), using 1\n",
 				argv[0], count);
 			count = 1;
+		} else if (count == 0) {
+			/*
+			 * don't bother setting anything else if the threads
+			 * are coming down anyway.
+			 */
+			goto set_threads;
 		}
 	}
 	/* KLUDGE ALERT:
@@ -157,28 +213,51 @@ main(int argc, char **argv)
 		(void) dup2(fd, 2);
 	}
 	closeall(3);
+	openlog("nfsd", LOG_PID, LOG_DAEMON);
 
-	sin.sin_family = AF_INET;
-	sin.sin_port = htons(port);
-	sin.sin_addr.s_addr = inet_addr(haddr);
+	/*
+	 * skip everything but setting of number of threads if sockets are
+	 * already open and in use.
+	 */
+	if (nfssvc_inuse())
+		goto set_threads;
 
 	/*
 	 * must set versions before the fd's so that the right versions get
 	 * registered with rpcbind. Note that on older kernels w/o the right
 	 * interfaces, these are a no-op.
 	 */
-	if (!nfssvc_inuse()) {
-		nfssvc_setvers(versbits);
+	nfssvc_setvers(versbits);
+
+	if (ipv4) {
+		sin.sin_family = AF_INET;
+		sin.sin_port = htons(port);
+		if (!haddr)
+			sin.sin_addr.s_addr = INADDR_ANY;
+
 		nfssvc_setfds(protobits, (struct sockaddr *) &sin, sizeof(sin));
 	}
 
-	openlog("nfsd", LOG_PID, LOG_DAEMON);
+	if (ipv6) {
+		sin6.sin6_family = AF_INET6;
+		sin6.sin6_port = htons(port);
+		if (!haddr)
+			sin6.sin6_addr = in6addr_any;
+
+		nfssvc_setfds(protobits, (struct sockaddr *) &sin6,
+				sizeof(sin6));
+	}
+
+set_threads:
 	if ((error = nfssvc_threads(port, count)) < 0) {
 		int e = errno;
 		syslog(LOG_ERR, "nfssvc: %s", strerror(e));
 		closelog();
 	}
 
+out:
+	free(haddr);
+	closelog();
 	return (error != 0);
 }
 
-- 
1.6.0.6


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3] nfs-utils: add IPv6 support to nfsd
  2009-05-11 17:58 ` [PATCH 3/3] nfs-utils: add IPv6 support to nfsd Jeff Layton
@ 2009-05-11 19:34   ` Chuck Lever
  2009-05-18 15:42     ` Steve Dickson
  0 siblings, 1 reply; 7+ messages in thread
From: Chuck Lever @ 2009-05-11 19:34 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-nfs

On May 11, 2009, at 1:58 PM, Jeff Layton wrote:
> Add 2 new options to rpc.nfsd -- -4 and -6. -4 makes it an IPv4-only
> server, and -6 makes it IPv6-only. Restructure the -H option so that
> if the address appears to be or resolves to an IPv4 address, that
> IPv6 is disabled. Ditto if it resolves to an IPv6 address.

For rpc.statd, I'm following Olaf's suggestion to use /etc/netconfig  
to decide what transports to use for listeners.  Basically, rpc.statd  
attempts to start listeners for all visible netids (marked with 'v')  
in /etc/netconfig.  This is how Solaris works, as I understand it.   
I'm planning to take this course for rpc.mountd as well.

Maybe rpc.nfsd should follow suit?

> Signed-off-by: Jeff Layton <jlayton@redhat.com>
> ---
> utils/nfsd/nfsd.c |  137 ++++++++++++++++++++++++++++++++++++++++ 
> +-----------
> 1 files changed, 108 insertions(+), 29 deletions(-)
>
> diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
> index 25babe1..0022e65 100644
> --- a/utils/nfsd/nfsd.c
> +++ b/utils/nfsd/nfsd.c
> @@ -41,7 +41,6 @@ static struct option longopts[] =
> };
> unsigned int protobits = NFSCTL_ALLBITS;
> unsigned int versbits = NFSCTL_ALLBITS;
> -char *haddr = NULL;
>
> int
> main(int argc, char **argv)
> @@ -49,7 +48,15 @@ main(int argc, char **argv)
> 	int	count = 1, c, error, port, fd, found_one;
> 	struct servent *ent;
> 	struct hostent *hp;
> -	struct sockaddr_in sin;
> +	struct sockaddr_in sin = { };
> +	struct sockaddr_in6 sin6 = { };
> +	char	*haddr = NULL;
> +	int	ipv4 = 1;
> +#ifdef IPV6_SUPPORTED
> +	int	ipv6 = 1;
> +#else  /* IPV6_SUPPORTED */
> +	int	ipv6 = 0;
> +#endif /* IPV6_SUPPORTED */
>
> 	ent = getservbyname ("nfs", "udp");
> 	if (ent != NULL)
> @@ -57,18 +64,12 @@ main(int argc, char **argv)
> 	else
> 		port = 2049;
>
> -	while ((c = getopt_long(argc, argv, "H:hN:p:P:TU", longopts,  
> NULL)) != EOF) {
> +	while ((c = getopt_long(argc, argv, "H:hN:p:P:TU46", longopts,  
> NULL)) != EOF) {
> 		switch(c) {
> 		case 'H':
> -			if (inet_addr(optarg) != INADDR_NONE) {
> -				haddr = strdup(optarg);
> -			} else if ((hp = gethostbyname(optarg)) != NULL) {
> -				haddr = inet_ntoa((*(struct in_addr*)(hp->h_addr_list[0])));
> -			} else {
> -				fprintf(stderr, "%s: Unknown hostname: %s\n",
> -					argv[0], optarg);
> -				usage(argv [0]);
> -			}
> +			/* we only deal with one host addr at the moment */
> +			free(haddr);
> +			haddr = strdup(optarg);
> 			break;
> 		case 'P':	/* XXX for nfs-server compatibility */
> 		case 'p':
> @@ -92,24 +93,76 @@ main(int argc, char **argv)
> 			}
> 			break;
> 		case 'T':
> -				NFSCTL_TCPUNSET(protobits);
> -				break;
> +			NFSCTL_TCPUNSET(protobits);
> +			break;
> 		case 'U':
> -				NFSCTL_UDPUNSET(protobits);
> -				break;
> +			NFSCTL_UDPUNSET(protobits);
> +			break;
> +		case '4':
> +			ipv6 = 0;
> +			break;
> +		case '6':
> +			ipv4 = 0;
> +			break;
> 		default:
> 			fprintf(stderr, "Invalid argument: '%c'\n", c);
> 		case 'h':
> 			usage(argv[0]);
> 		}
> 	}
> -	/*
> -	 * Do some sanity checking, if the ctlbits are set
> -	 */
> +
> +	/* sanity checks */
> +
> +	/* if an address was specified, check it first */
> +	if (haddr) {
> +		/* does it look like an addr of some sort? */
> +		if (inet_pton(AF_INET, haddr, &sin.sin_addr)) {
> +			ipv6 = 0;
> +			goto family_check;
> +		} else if (inet_pton(AF_INET6, haddr, &sin6.sin6_addr)) {
> +			ipv4 = 0;
> +			goto family_check;
> +		}
> +
> +		/* see if it's a hostname */
> +		hp = gethostbyname(haddr);
> +		if (!hp) {
> +			fprintf(stderr, "%s: gethostbyname on %s failed: %d\n",
> +					argv[0], haddr, h_errno);
> +			error = h_errno;
> +			usage(argv[0]);
> +		}
> +
> +		if (hp->h_addrtype == AF_INET) {
> +			ipv6 = 0;
> +			memcpy(&sin.sin_addr, hp->h_addr_list[0],
> +			       hp->h_length);
> +			if (sin.sin_addr == INADDR_NONE) {
> +				fprintf(stderr, "%s: Bad hostaddr %s\n",
> +						argv[0], haddr);
> +				usage(argv[0]);
> +			}
> +		} else if (hp->h_addrtype == AF_INET6) {
> +			ipv4 = 0;
> +			memcpy(&sin6.sin6_addr, hp->h_addr_list[0],
> +			       hp->h_length);
> +		}
> +	}
> +
> +family_check:
> +	/* make sure at least one address family is enabled */
> +	if (!ipv4 && !ipv6) {
> +		fprintf(stderr, "no address families enabled\n");
> +		exit(1);
> +	}
> +
> +	/* make sure at least one protocol type is enabled */
> 	if (!NFSCTL_UDPISSET(protobits) && !NFSCTL_TCPISSET(protobits)) {
> 		fprintf(stderr, "invalid protocol specified\n");
> 		exit(1);
> 	}
> +
> +	/* make sure that at least one version is enabled */
> 	found_one = 0;
> 	for (c = NFSD_MINVERS; c <= NFSD_MAXVERS; c++) {
> 		if (NFSCTL_VERISSET(versbits, c))
> @@ -120,14 +173,11 @@ main(int argc, char **argv)
> 		exit(1);
> 	}			
>
> +	/* must have TCP for NFSv4 */
> 	if (NFSCTL_VERISSET(versbits, 4) && !NFSCTL_TCPISSET(protobits)) {
> 		fprintf(stderr, "version 4 requires the TCP protocol\n");
> 		exit(1);
> 	}
> -	if (haddr == NULL) {
> -		struct in_addr in = {INADDR_ANY};
> -		haddr = strdup(inet_ntoa(in));
> -	}
>
> 	if (chdir(NFS_STATEDIR)) {
> 		fprintf(stderr, "%s: chdir(%s) failed: %s\n",
> @@ -142,6 +192,12 @@ main(int argc, char **argv)
> 				"%s: invalid server count (%d), using 1\n",
> 				argv[0], count);
> 			count = 1;
> +		} else if (count == 0) {
> +			/*
> +			 * don't bother setting anything else if the threads
> +			 * are coming down anyway.
> +			 */
> +			goto set_threads;
> 		}
> 	}
> 	/* KLUDGE ALERT:
> @@ -157,28 +213,51 @@ main(int argc, char **argv)
> 		(void) dup2(fd, 2);
> 	}
> 	closeall(3);
> +	openlog("nfsd", LOG_PID, LOG_DAEMON);
>
> -	sin.sin_family = AF_INET;
> -	sin.sin_port = htons(port);
> -	sin.sin_addr.s_addr = inet_addr(haddr);
> +	/*
> +	 * skip everything but setting of number of threads if sockets are
> +	 * already open and in use.
> +	 */
> +	if (nfssvc_inuse())
> +		goto set_threads;
>
> 	/*
> 	 * must set versions before the fd's so that the right versions get
> 	 * registered with rpcbind. Note that on older kernels w/o the right
> 	 * interfaces, these are a no-op.
> 	 */
> -	if (!nfssvc_inuse()) {
> -		nfssvc_setvers(versbits);
> +	nfssvc_setvers(versbits);
> +
> +	if (ipv4) {
> +		sin.sin_family = AF_INET;
> +		sin.sin_port = htons(port);
> +		if (!haddr)
> +			sin.sin_addr.s_addr = INADDR_ANY;
> +
> 		nfssvc_setfds(protobits, (struct sockaddr *) &sin, sizeof(sin));
> 	}
>
> -	openlog("nfsd", LOG_PID, LOG_DAEMON);
> +	if (ipv6) {
> +		sin6.sin6_family = AF_INET6;
> +		sin6.sin6_port = htons(port);
> +		if (!haddr)
> +			sin6.sin6_addr = in6addr_any;
> +
> +		nfssvc_setfds(protobits, (struct sockaddr *) &sin6,
> +				sizeof(sin6));
> +	}
> +
> +set_threads:
> 	if ((error = nfssvc_threads(port, count)) < 0) {
> 		int e = errno;
> 		syslog(LOG_ERR, "nfssvc: %s", strerror(e));
> 		closelog();
> 	}
>
> +out:
> +	free(haddr);
> +	closelog();
> 	return (error != 0);
> }
>
> -- 
> 1.6.0.6
>

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3] nfs-utils: add IPv6 support to nfsd
  2009-05-11 19:34   ` Chuck Lever
@ 2009-05-18 15:42     ` Steve Dickson
       [not found]       ` <4A1181EE.7080401-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Steve Dickson @ 2009-05-18 15:42 UTC (permalink / raw)
  To: Chuck Lever; +Cc: Jeff Layton, linux-nfs



Chuck Lever wrote:
> On May 11, 2009, at 1:58 PM, Jeff Layton wrote:
>> Add 2 new options to rpc.nfsd -- -4 and -6. -4 makes it an IPv4-only
>> server, and -6 makes it IPv6-only. Restructure the -H option so that
>> if the address appears to be or resolves to an IPv4 address, that
>> IPv6 is disabled. Ditto if it resolves to an IPv6 address.
> 
> For rpc.statd, I'm following Olaf's suggestion to use /etc/netconfig to
> decide what transports to use for listeners.  Basically, rpc.statd
> attempts to start listeners for all visible netids (marked with 'v') in
> /etc/netconfig.  This is how Solaris works, as I understand it.  I'm
> planning to take this course for rpc.mountd as well.
> 
> Maybe rpc.nfsd should follow suit?
I would have to agree... Jeff, what do you think?

steved.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 3/3] nfs-utils: add IPv6 support to nfsd
       [not found]       ` <4A1181EE.7080401-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
@ 2009-05-18 15:48         ` Jeff Layton
  0 siblings, 0 replies; 7+ messages in thread
From: Jeff Layton @ 2009-05-18 15:48 UTC (permalink / raw)
  To: Steve Dickson; +Cc: Chuck Lever, linux-nfs

On Mon, 18 May 2009 11:42:38 -0400
Steve Dickson <SteveD@redhat.com> wrote:

> 
> 
> Chuck Lever wrote:
> > On May 11, 2009, at 1:58 PM, Jeff Layton wrote:
> >> Add 2 new options to rpc.nfsd -- -4 and -6. -4 makes it an IPv4-only
> >> server, and -6 makes it IPv6-only. Restructure the -H option so that
> >> if the address appears to be or resolves to an IPv4 address, that
> >> IPv6 is disabled. Ditto if it resolves to an IPv6 address.
> > 
> > For rpc.statd, I'm following Olaf's suggestion to use /etc/netconfig to
> > decide what transports to use for listeners.  Basically, rpc.statd
> > attempts to start listeners for all visible netids (marked with 'v') in
> > /etc/netconfig.  This is how Solaris works, as I understand it.  I'm
> > planning to take this course for rpc.mountd as well.
> > 
> > Maybe rpc.nfsd should follow suit?
> I would have to agree... Jeff, what do you think?

Definitely agree. Once I'm through playing whack-a-mole on some CIFS
issues, I plan to sit down and look at incorporating that. Thanks for
having a look.

-- 
Jeff Layton <jlayton@redhat.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2009-05-18 15:48 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-05-11 17:58 [PATCH 0/3] nfs-utils: add IPv6 support to rpc.nfsd (RFC) Jeff Layton
2009-05-11 17:58 ` [PATCH 1/3] nfs-utils: rearrange nfssvc.c Jeff Layton
2009-05-11 17:58 ` [PATCH 2/3] nfs-utils: set IPV6_V6ONLY on nfssvc IPv6 sockets Jeff Layton
2009-05-11 17:58 ` [PATCH 3/3] nfs-utils: add IPv6 support to nfsd Jeff Layton
2009-05-11 19:34   ` Chuck Lever
2009-05-18 15:42     ` Steve Dickson
     [not found]       ` <4A1181EE.7080401-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
2009-05-18 15:48         ` Jeff Layton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox