public inbox for linux-nfs@vger.kernel.org
 help / color / mirror / Atom feed
From: Chuck Lever <chuck.lever@oracle.com>
To: Jeff Layton <jlayton@redhat.com>
Cc: linux-nfs@vger.kernel.org, steved@redhat.com
Subject: Re: [PATCH 4/5] nfs-utils: add IPv6 support to nfsd
Date: Wed, 27 May 2009 12:22:57 -0400	[thread overview]
Message-ID: <08EFB0AF-CE3B-4B21-9D6D-33EEBFCDC39E@oracle.com> (raw)
In-Reply-To: <1243425275-6284-5-git-send-email-jlayton@redhat.com>


On May 27, 2009, at 7:54 AM, Jeff Layton wrote:

> Add support for handing off IPv6 sockets to the kernel for nfsd. One  
> of
> the main goals here is to not change the behavior of options and not  
> to
> add any new ones, so this patch attempts to do that.
>
> We also don't want to break anything in the event that someone has an
> rpc.nfsd program built with IPv6 capability, but the knfsd doesn't
> support IPv6. Ditto for the cases where IPv6 is either not compiled in
> or is compiled in and blacklisted.
>
> Signed-off-by: Jeff Layton <jlayton@redhat.com>
> ---
> utils/nfsd/nfsd.c |  158 +++++++++++++++++++++++++++++++++++++++++ 
> +-----------
> 1 files changed, 125 insertions(+), 33 deletions(-)
>
> diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
> index 2a3cd0a..77c7e1b 100644
> --- a/utils/nfsd/nfsd.c
> +++ b/utils/nfsd/nfsd.c
> @@ -41,17 +41,24 @@ static struct option longopts[] =
> };
> unsigned int protobits = NFSCTL_ALLBITS;
> unsigned int versbits = NFSCTL_ALLBITS;
> -int minorvers4 = NFSD_MAXMINORVERS4;		/* nfsv4 minor version */
> -char *haddr = NULL;
>
> int
> main(int argc, char **argv)
> {
> -	int	count = 1, c, error, port, fd, found_one;
> +	int	count = 1, c, error = 0, port, fd, found_one;
> 	struct servent *ent;
> 	struct hostent *hp;
> 	char *p;
> -	struct sockaddr_in sin;
> +	struct sockaddr_in sin = { };
> +	struct sockaddr_in6 sin6 = { };
> +	int minorvers4 = NFSD_MAXMINORVERS4;	/* nfsv4 minor version */
> +	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)
> @@ -62,15 +69,9 @@ main(int argc, char **argv)
> 	while ((c = getopt_long(argc, argv, "H:hN:p:P:TU", 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':
> @@ -98,24 +99,79 @@ 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;

Clean up: separate patch?

> 		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;
> +		}

Using getaddrinfo(3) with AI_NUMERICHOST might allow a lot of  
simplification here.  See utils/new-statd/hostname.c in my repo for  
some possibilities.

You could also easily pass the text version of the -p option into  
getaddrinfo() to have it plant the port number into the bind address.

This logic is complex enough that you may want to extract it into a  
helper anyway.

> +
> +		/* 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]);
> +		}
> +
> +		switch (hp->h_addrtype) {
> +		case AF_INET:
> +			ipv6 = 0;
> +			memcpy(&sin.sin_addr, hp->h_addr_list[0],
> +			       hp->h_length);
> +			if (sin.sin_addr.s_addr == INADDR_NONE) {
> +				fprintf(stderr, "%s: Bad hostaddr %s\n",
> +						argv[0], haddr);
> +				usage(argv[0]);
> +			}
> +			break;
> +#ifdef IPV6_SUPPORTED
> +		case AF_INET6:
> +			ipv4 = 0;
> +			memcpy(&sin6.sin6_addr, hp->h_addr_list[0],
> +			       hp->h_length);
> +			break;
> +#endif /* IPV6_SUPPORTED */
> +		default:
> +			fprintf(stderr, "%s: unsupported address family %d\n",
> +					argv[0], hp->h_addrtype);
> +			exit(0);
> +		}
> +	}
> +
> +family_check:
> +	/* make sure at least one address family is enabled */
> +	if (!ipv4 && !ipv6) {
> +		fprintf(stderr, "no address families enabled\n");
> +		exit(1);
> +	}

Is this needed if you don't have -4 and -6?  I'm still familiarizing  
myself with these patches, but I have a vague feeling that this  
checking could be made much simpler, especially if the netconfig- 
related logic was introduced at the same time rather than in a  
separate patch.

> +
> +	/* 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))
> @@ -126,14 +182,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",
> @@ -148,6 +201,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:
> @@ -163,24 +222,55 @@ main(int argc, char **argv)
> 		(void) dup2(fd, 2);
> 	}
> 	closeall(3);
> +	openlog("nfsd", LOG_PID, LOG_DAEMON);

Might be nice if rpc.nfsd used xlog() instead.  Maybe for another day.

> -	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, minorvers4);
> -		error = nfssvc_setfds(protobits, (struct sockaddr *) &sin,  
> sizeof(sin));
> -		if (error)
> -			goto out;
> +	nfssvc_setvers(versbits, minorvers4);
> +
> +	if (ipv4) {
> +		sin.sin_family = AF_INET;
> +		sin.sin_port = htons(port);
> +		if (!haddr)
> +			sin.sin_addr.s_addr = INADDR_ANY;
> +
> +		if (nfssvc_setfds(protobits, (struct sockaddr *) &sin,  
> sizeof(sin)))
> +			ipv4 = 0;
> 	}
>
> -	openlog("nfsd", LOG_PID, LOG_DAEMON);
> +#ifdef IPV6_SUPPORTED
> +	if (ipv6) {
> +		sin6.sin6_family = AF_INET6;
> +		sin6.sin6_port = htons(port);
> +		if (!haddr)
> +			sin6.sin6_addr = in6addr_any;
> +
> +		if (nfssvc_setfds(protobits, (struct sockaddr *) &sin6,  
> sizeof(sin6)))
> +			ipv6 = 0;
> +	}
> +#endif /* IPV6_SUPPORTED */
> +
> +	/*
> +	 * if ipv4 and ipv6 are both 0 here, then we were unable to pass  
> off sockets
> +	 * to the kernel. Don't try to bring up any threads.
> +	 */
> +	if (!ipv4 && !ipv6 && count > 0) {
> +		syslog(LOG_ERR, "nfssvc: failed to hand off sockets to kernel\n");
> +		error = -1;
> +		goto out;
> +	}
> +
> +set_threads:
> 	if ((error = nfssvc_threads(port, count)) < 0) {
> 		int e = errno;
> 		syslog(LOG_ERR, "nfssvc: %s", strerror(e));
> @@ -188,6 +278,8 @@ main(int argc, char **argv)
> 	}
>
> out:
> +	free(haddr);
> +	closelog();
> 	return (error != 0);
> }
>
> -- 
> 1.6.0.6
>

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

  reply	other threads:[~2009-05-27 16:23 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-27 11:54 [PATCH 0/5] nfs-utils: add IPv6 support for rpc.nfsd (try #3) Jeff Layton
2009-05-27 11:54 ` [PATCH 1/5] nfs-utils: don't link libexport.a and libmisc.a to nfsd Jeff Layton
2009-05-27 11:54 ` [PATCH 2/5] nfs-utils: break up nfssvc.c into more individually callable functions Jeff Layton
2009-05-27 11:54 ` [PATCH 3/5] nfs-utils: set IPV6_V6ONLY on nfssvc IPv6 sockets Jeff Layton
2009-05-27 11:54 ` [PATCH 4/5] nfs-utils: add IPv6 support to nfsd Jeff Layton
2009-05-27 16:22   ` Chuck Lever [this message]
2009-05-29 11:08     ` Jeff Layton
2009-05-27 11:54 ` [PATCH 5/5] nfs-utils: limit protocols and families used by nfsd to those listed in /etc/netconfig Jeff Layton
2009-05-27 16:30   ` Chuck Lever
2009-05-29 11:20     ` Jeff Layton
     [not found]       ` <20090529072050.0f24e385-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2009-05-29 15:30         ` Chuck Lever

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=08EFB0AF-CE3B-4B21-9D6D-33EEBFCDC39E@oracle.com \
    --to=chuck.lever@oracle.com \
    --cc=jlayton@redhat.com \
    --cc=linux-nfs@vger.kernel.org \
    --cc=steved@redhat.com \
    /path/to/YOUR_REPLY

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

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