change nfs boot behaviour to automatically try next boot method if boot information are incomplete to succeed. trunk
authorcegger <cegger@NetBSD.org>
Mon, 27 Oct 2008 10:58:22 +0000
branchtrunk
changeset 174541 181fe45f03e7
parent 174540 7b592c252b77
child 174542 824dec905af3
change nfs boot behaviour to automatically try next boot method if boot information are incomplete to succeed. That way, it is possible combine static and dhcp boot: For example, to boot diskless you can specify the nfs-server and the rootpath statically. All other information will be taken via dhcp. Patch has been presented on port-xen, tech-kern and tech-net: http://mail-index.netbsd.org/port-xen/2008/10/24/msg004488.html http://mail-index.netbsd.org/tech-kern/2008/10/24/msg003255.html http://mail-index.netbsd.org/tech-net/2008/10/24/msg000864.html No comments, no objections.
sys/arch/xen/x86/autoconf.c
sys/arch/xen/xen/if_xennet.c
sys/arch/xen/xen/if_xennet_xenbus.c
sys/nfs/nfs_boot.c
sys/nfs/nfs_bootdhcp.c
sys/nfs/nfs_bootparam.c
sys/nfs/nfs_bootstatic.c
sys/nfs/nfsdiskless.h
--- a/sys/arch/xen/x86/autoconf.c	Mon Oct 27 08:27:04 2008 +0000
+++ b/sys/arch/xen/x86/autoconf.c	Mon Oct 27 10:58:22 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: autoconf.c,v 1.6 2008/10/24 16:37:25 cegger Exp $	*/
+/*	$NetBSD: autoconf.c,v 1.7 2008/10/27 10:58:22 cegger Exp $	*/
 /*	NetBSD: autoconf.c,v 1.75 2003/12/30 12:33:22 pk Exp 	*/
 
 /*-
@@ -45,7 +45,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.6 2008/10/24 16:37:25 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.7 2008/10/27 10:58:22 cegger Exp $");
 
 #include "opt_xen.h"
 #include "opt_compat_oldboot.h"
@@ -232,6 +232,7 @@
 #if 0
 	struct ifnet *ifp = nd->nd_ifp;
 #endif
+	int flags = 0;
 	union xen_cmdline_parseinfo xcp;
 	struct sockaddr_in *sin;
 
@@ -240,6 +241,12 @@
 	xcp.xcp_netinfo.xi_root = nd->nd_root.ndm_host;
 	xen_parse_cmdline(XEN_PARSE_NETINFO, &xcp);
 
+	if (xcp.xcp_netinfo.xi_root[0] != '\0') {
+		flags |= NFS_BOOT_HAS_SERVER;
+		if (strchr(xcp.xcp_netinfo.xi_root, ':') != NULL)
+			flags |= NFS_BOOT_HAS_ROOTPATH;
+	}
+
 	nd->nd_myip.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[0]);
 	nd->nd_gwip.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[2]);
 	nd->nd_mask.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[3]);
@@ -250,12 +257,16 @@
 	sin->sin_family = AF_INET;
 	sin->sin_addr.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[1]);
 
-	if (nd->nd_myip.s_addr == 0)
-		return NFS_BOOTSTATIC_NOSTATIC;
-	else
-		return (NFS_BOOTSTATIC_HAS_MYIP|NFS_BOOTSTATIC_HAS_GWIP|
-		    NFS_BOOTSTATIC_HAS_MASK|NFS_BOOTSTATIC_HAS_SERVADDR|
-		    NFS_BOOTSTATIC_HAS_SERVER);
+	if (nd->nd_myip.s_addr)
+		flags |= NFS_BOOT_HAS_MYIP;
+	if (nd->nd_gwip.s_addr)
+		flags |= NFS_BOOT_HAS_GWIP;
+	if (nd->nd_mask.s_addr)
+		flags |= NFS_BOOT_HAS_MASK;
+	if (sin->sin_addr.s_addr)
+		flags |= NFS_BOOT_HAS_SERVADDR;
+
+	return flags;
 }
 #endif
 
--- a/sys/arch/xen/xen/if_xennet.c	Mon Oct 27 08:27:04 2008 +0000
+++ b/sys/arch/xen/xen/if_xennet.c	Mon Oct 27 10:58:22 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_xennet.c,v 1.59 2008/10/21 15:46:32 cegger Exp $	*/
+/*	$NetBSD: if_xennet.c,v 1.60 2008/10/27 10:58:22 cegger Exp $	*/
 
 /*
  *
@@ -33,7 +33,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_xennet.c,v 1.59 2008/10/21 15:46:32 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_xennet.c,v 1.60 2008/10/27 10:58:22 cegger Exp $");
 
 #include "opt_inet.h"
 #include "opt_nfs_boot.h"
@@ -1287,6 +1287,7 @@
 int
 xennet_bootstatic_callback(struct nfs_diskless *nd)
 {
+	int flags = 0;
 	struct ifnet *ifp = nd->nd_ifp;
 	struct xennet_softc *sc = ifp->if_softc;
 	union xen_cmdline_parseinfo xcp;
@@ -1297,6 +1298,12 @@
 	xcp.xcp_netinfo.xi_root = nd->nd_root.ndm_host;
 	xen_parse_cmdline(XEN_PARSE_NETINFO, &xcp);
 
+	if (xcp.xcp_netinfo.xi_root[0] != '\0') {
+		flags |= NFS_BOOT_HAS_SERVER;
+		if (strchr(xcp.xcp_netinfo.xi_root, ':') != NULL)
+			flags |= NFS_BOOT_HAS_ROOTPATH;
+	}
+
 	nd->nd_myip.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[0]);
 	nd->nd_gwip.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[2]);
 	nd->nd_mask.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[3]);
@@ -1307,12 +1314,16 @@
 	sin->sin_family = AF_INET;
 	sin->sin_addr.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[1]);
 
-	if (nd->nd_myip.s_addr == 0)
-		return NFS_BOOTSTATIC_NOSTATIC;
-	else
-		return (NFS_BOOTSTATIC_HAS_MYIP|NFS_BOOTSTATIC_HAS_GWIP|
-		    NFS_BOOTSTATIC_HAS_MASK|NFS_BOOTSTATIC_HAS_SERVADDR|
-		    NFS_BOOTSTATIC_HAS_SERVER);
+	if (nd->nd_myip.s_addr)
+		flags |= NFS_BOOT_HAS_MYIP;
+	if (nd->nd_gwip.s_addr)
+		flags |= NFS_BOOT_HAS_GWIP;
+	if (nd->nd_mask.s_addr)
+		flags |= NFS_BOOT_HAS_MASK;
+	if (sin->sin_addr.s_addr)
+		flags |= NFS_BOOT_HAS_SERVADDR;
+
+	return flags;
 }
 #endif /* defined(NFS_BOOT_BOOTSTATIC) */
 
--- a/sys/arch/xen/xen/if_xennet_xenbus.c	Mon Oct 27 08:27:04 2008 +0000
+++ b/sys/arch/xen/xen/if_xennet_xenbus.c	Mon Oct 27 10:58:22 2008 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: if_xennet_xenbus.c,v 1.27 2008/10/25 17:12:29 jym Exp $      */
+/*      $NetBSD: if_xennet_xenbus.c,v 1.28 2008/10/27 10:58:22 cegger Exp $      */
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.27 2008/10/25 17:12:29 jym Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_xennet_xenbus.c,v 1.28 2008/10/27 10:58:22 cegger Exp $");
 
 #include "opt_xen.h"
 #include "opt_nfs_boot.h"
@@ -1158,6 +1158,7 @@
 	struct xennet_xenbus_softc *sc =
 	    (struct xennet_xenbus_softc *)ifp->if_softc;
 #endif
+	int flags = 0;
 	union xen_cmdline_parseinfo xcp;
 	struct sockaddr_in *sin;
 
@@ -1166,6 +1167,12 @@
 	xcp.xcp_netinfo.xi_root = nd->nd_root.ndm_host;
 	xen_parse_cmdline(XEN_PARSE_NETINFO, &xcp);
 
+	if (xcp.xcp_netinfo.xi_root[0] != '\0') {
+		flags |= NFS_BOOT_HAS_SERVER;
+		if (strchr(xcp.xcp_netinfo.xi_root, ':') != NULL)
+			flags |= NFS_BOOT_HAS_ROOTPATH;
+	}
+
 	nd->nd_myip.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[0]);
 	nd->nd_gwip.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[2]);
 	nd->nd_mask.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[3]);
@@ -1175,12 +1182,17 @@
 	sin->sin_len = sizeof(*sin);
 	sin->sin_family = AF_INET;
 	sin->sin_addr.s_addr = ntohl(xcp.xcp_netinfo.xi_ip[1]);
-	if (nd->nd_myip.s_addr == 0)
-		return NFS_BOOTSTATIC_NOSTATIC;
-	else
-		return (NFS_BOOTSTATIC_HAS_MYIP|NFS_BOOTSTATIC_HAS_GWIP|
-		    NFS_BOOTSTATIC_HAS_MASK|NFS_BOOTSTATIC_HAS_SERVADDR|
-		    NFS_BOOTSTATIC_HAS_SERVER);
+
+	if (nd->nd_myip.s_addr)
+		flags |= NFS_BOOT_HAS_MYIP;
+	if (nd->nd_gwip.s_addr)
+		flags |= NFS_BOOT_HAS_GWIP;
+	if (nd->nd_mask.s_addr)
+		flags |= NFS_BOOT_HAS_MASK;
+	if (sin->sin_addr.s_addr)
+		flags |= NFS_BOOT_HAS_SERVADDR;
+
+	return flags;
 }
 #endif /* defined(NFS_BOOT_BOOTSTATIC) */
 
--- a/sys/nfs/nfs_boot.c	Mon Oct 27 08:27:04 2008 +0000
+++ b/sys/nfs/nfs_boot.c	Mon Oct 27 10:58:22 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_boot.c,v 1.75 2008/10/24 17:17:12 cegger Exp $	*/
+/*	$NetBSD: nfs_boot.c,v 1.76 2008/10/27 10:58:22 cegger Exp $	*/
 
 /*-
  * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_boot.c,v 1.75 2008/10/24 17:17:12 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_boot.c,v 1.76 2008/10/27 10:58:22 cegger Exp $");
 
 #include "opt_nfs.h"
 #include "opt_tftproot.h"
@@ -106,6 +106,7 @@
 {
 	struct ifnet *ifp;
 	int error = 0;
+	int flags = 0;
 
 	/*
 	 * Find the network interface.
@@ -122,7 +123,7 @@
 #if defined(NFS_BOOT_BOOTSTATIC)
 	if (error && nfs_boot_bootstatic) {
 		printf("nfs_boot: trying static\n");
-		error = nfs_bootstatic(nd, lwp);
+		error = nfs_bootstatic(nd, lwp, &flags);
 	}
 #endif
 #if defined(NFS_BOOT_BOOTP) || defined(NFS_BOOT_DHCP)
@@ -132,13 +133,13 @@
 #else
 		printf("nfs_boot: trying BOOTP\n");
 #endif
-		error = nfs_bootdhcp(nd, lwp);
+		error = nfs_bootdhcp(nd, lwp, &flags);
 	}
 #endif
 #ifdef NFS_BOOT_BOOTPARAM
 	if (error && nfs_boot_bootparam) {
 		printf("nfs_boot: trying RARP (and RPC/bootparam)\n");
-		error = nfs_bootparam(nd, lwp);
+		error = nfs_bootparam(nd, lwp, &flags);
 	}
 #endif
 	if (error)
@@ -528,6 +529,8 @@
  * Get an initial NFS file handle using Sun RPC/mountd.
  * Separate function because we used to call it twice.
  * (once for root and once for swap)
+ *
+ * ndm  output
  */
 static int
 nfs_boot_getfh(struct nfs_dlmount *ndm, struct lwp *l)
--- a/sys/nfs/nfs_bootdhcp.c	Mon Oct 27 08:27:04 2008 +0000
+++ b/sys/nfs/nfs_bootdhcp.c	Mon Oct 27 10:58:22 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_bootdhcp.c,v 1.43 2008/10/24 17:17:12 cegger Exp $	*/
+/*	$NetBSD: nfs_bootdhcp.c,v 1.44 2008/10/27 10:58:22 cegger Exp $	*/
 
 /*-
  * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@@ -44,7 +44,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_bootdhcp.c,v 1.43 2008/10/24 17:17:12 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_bootdhcp.c,v 1.44 2008/10/27 10:58:22 cegger Exp $");
 
 #include "opt_nfs_boot.h"
 #include "opt_tftproot.h"
@@ -217,8 +217,8 @@
 /* Convenience macro */
 #define INTOHL(ina) ((u_int32_t)ntohl((ina).s_addr))
 
-static int bootpc_call (struct nfs_diskless *, struct lwp *);
-static void bootp_extract (struct bootp *, int, struct nfs_diskless *);
+static int bootpc_call (struct nfs_diskless *, struct lwp *, int *);
+static void bootp_extract (struct bootp *, int, struct nfs_diskless *, int *);
 
 #ifdef	DEBUG_NFS_BOOT_DHCP
 #define DPRINTF(s)  printf s
@@ -231,7 +231,7 @@
  * Get our boot parameters using BOOTP.
  */
 int
-nfs_bootdhcp(struct nfs_diskless *nd, struct lwp *lwp)
+nfs_bootdhcp(struct nfs_diskless *nd, struct lwp *lwp, int *flags)
 {
 	struct ifnet *ifp = nd->nd_ifp;
 	int error;
@@ -240,15 +240,17 @@
 	 * Do enough of ifconfig(8) so that the chosen interface
 	 * can talk to the servers.  Use address zero for now.
 	 */
-	error = nfs_boot_setaddress(ifp, lwp, INADDR_ANY, INADDR_ANY,
-				    INADDR_BROADCAST);
+	error = nfs_boot_setaddress(ifp, lwp,
+		*flags & NFS_BOOT_HAS_MYIP ? nd->nd_myip.s_addr : INADDR_ANY,
+		*flags & NFS_BOOT_HAS_MASK ? nd->nd_mask.s_addr : INADDR_ANY,
+		    INADDR_BROADCAST);
 	if (error) {
 		printf("nfs_boot: set ifaddr zero, error=%d\n", error);
 		return (error);
 	}
 
 	/* This function call does the real send/recv work. */
-	error = bootpc_call(nd, lwp);
+	error = bootpc_call(nd, lwp, flags);
 
 	/* Get rid of the temporary (zero) IP address. */
 	(void) nfs_boot_deladdress(ifp, lwp, INADDR_ANY);
@@ -267,6 +269,9 @@
 		goto out;
 	}
 
+	if ((*flags & NFS_BOOT_ALLINFO) != NFS_BOOT_ALLINFO)
+		return EADDRNOTAVAIL;
+
 out:
 	if (error) {
 		(void) nfs_boot_ifupdown(ifp, lwp, 0);
@@ -436,7 +441,7 @@
 }
 
 static int
-bootpc_call(struct nfs_diskless *nd, struct lwp *lwp)
+bootpc_call(struct nfs_diskless *nd, struct lwp *lwp, int *flags)
 {
 	struct socket *so;
 	struct ifnet *ifp = nd->nd_ifp;
@@ -649,7 +654,7 @@
 #endif
 	       inet_ntoa(bpc.replybuf->bp_siaddr));
 
-	bootp_extract(bpc.replybuf, bpc.replylen, nd);
+	bootp_extract(bpc.replybuf, bpc.replylen, nd, flags);
 
 out:
 	if (bpc.replybuf)
@@ -663,7 +668,8 @@
 }
 
 static void
-bootp_extract(struct bootp *bootp, int replylen, struct nfs_diskless *nd)
+bootp_extract(struct bootp *bootp, int replylen,
+		struct nfs_diskless *nd, int *flags)
 {
 	struct sockaddr_in *sin;
 	struct in_addr netmask;
@@ -777,49 +783,71 @@
 		domainnamelen = mydomainlen;
 		printf("nfs_boot: my_domain=%s\n", domainname);
 	}
-	nd->nd_myip = bootp->bp_yiaddr;
-	if (nd->nd_myip.s_addr)
+	if (!(*flags & NFS_BOOT_HAS_MYIP)) {
+		nd->nd_myip = bootp->bp_yiaddr;
 		printf("nfs_boot: my_addr=%s\n", inet_ntoa(nd->nd_myip));
-	nd->nd_mask = netmask;
-	if (nd->nd_mask.s_addr)
+		*flags |= NFS_BOOT_HAS_MYIP;
+	}
+	if (!(*flags & NFS_BOOT_HAS_MASK)) {
+		nd->nd_mask = netmask;
 		printf("nfs_boot: my_mask=%s\n", inet_ntoa(nd->nd_mask));
-	nd->nd_gwip = gateway;
-	if (nd->nd_gwip.s_addr)
+		*flags |= NFS_BOOT_HAS_MASK;
+	}
+	if (!(*flags & NFS_BOOT_HAS_GWIP)) {
+		nd->nd_gwip = gateway;
 		printf("nfs_boot: gateway=%s\n", inet_ntoa(nd->nd_gwip));
+		*flags |= NFS_BOOT_HAS_GWIP;
+	}
 
 	/*
 	 * Store the information about our NFS root mount.
 	 * The caller will print it, so be silent here.
 	 */
-	{
+	do {
 		struct nfs_dlmount *ndm = &nd->nd_root;
 
-		/* Server IP address. */
-		sin = (struct sockaddr_in *) &ndm->ndm_saddr;
-		memset((void *)sin, 0, sizeof(*sin));
-		sin->sin_len = sizeof(*sin);
-		sin->sin_family = AF_INET;
-		sin->sin_addr = rootserver;
-		/* Server name. */
-		if (!overloaded && bootp->bp_sname[0] != 0 &&
-		    !memcmp(&rootserver, &bootp->bp_siaddr,
-			  sizeof(struct in_addr))) {
-			/* standard root server, we have the name */
-			strncpy(ndm->ndm_host, bootp->bp_sname, BP_SNAME_LEN-1);
-		} else {
-			/* Show the server IP address numerically. */
-			strncpy(ndm->ndm_host, inet_ntoa(rootserver),
-				BP_SNAME_LEN-1);
+
+		if (!(*flags & NFS_BOOT_HAS_SERVADDR)) {
+			/* Server IP address. */
+			sin = (struct sockaddr_in *) &ndm->ndm_saddr;
+			memset((void *)sin, 0, sizeof(*sin));
+			sin->sin_len = sizeof(*sin);
+			sin->sin_family = AF_INET;
+			sin->sin_addr = rootserver;
+			*flags |= NFS_BOOT_HAS_SERVADDR;
 		}
-		len = strlen(ndm->ndm_host);
-		if (rootpath &&
-		    len + 1 + rootpathlen + 1 <= sizeof(ndm->ndm_host)) {
-			ndm->ndm_host[len++] = ':';
-			strncpy(ndm->ndm_host + len,
-				rootpath, rootpathlen);
-			ndm->ndm_host[len + rootpathlen] = '\0';
-		} /* else: upper layer will handle error */
-	}
+
+		if (!(*flags & NFS_BOOT_HAS_SERVER)) {
+			/* Server name. */
+			if (!overloaded && bootp->bp_sname[0] != 0 &&
+			    !memcmp(&rootserver, &bootp->bp_siaddr,
+				  sizeof(struct in_addr)))
+			{
+				/* standard root server, we have the name */
+				strncpy(ndm->ndm_host, bootp->bp_sname,
+					BP_SNAME_LEN-1);
+				*flags |= NFS_BOOT_HAS_SERVER;
+			} else {
+				/* Show the server IP address numerically. */
+				strncpy(ndm->ndm_host, inet_ntoa(rootserver),
+					BP_SNAME_LEN-1);
+				*flags |= NFS_BOOT_HAS_SERVER;
+			}
+		}
+
+		if (!(*flags & NFS_BOOT_HAS_ROOTPATH)) {
+			len = strlen(ndm->ndm_host);
+			if (rootpath &&
+			    len + 1 + rootpathlen + 1 <= sizeof(ndm->ndm_host))
+			{
+				ndm->ndm_host[len++] = ':';
+				strncpy(ndm->ndm_host + len,
+					rootpath, rootpathlen);
+				ndm->ndm_host[len + rootpathlen] = '\0';
+				*flags |= NFS_BOOT_HAS_ROOTPATH;
+			} /* else: upper layer will handle error */
+		}
+	} while(0);
 
 #ifdef TFTPROOT
 #if BP_FILE_LEN > MNAMELEN
--- a/sys/nfs/nfs_bootparam.c	Mon Oct 27 08:27:04 2008 +0000
+++ b/sys/nfs/nfs_bootparam.c	Mon Oct 27 10:58:22 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_bootparam.c,v 1.33 2008/10/24 17:17:12 cegger Exp $	*/
+/*	$NetBSD: nfs_bootparam.c,v 1.34 2008/10/27 10:58:22 cegger Exp $	*/
 
 /*-
  * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_bootparam.c,v 1.33 2008/10/24 17:17:12 cegger Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_bootparam.c,v 1.34 2008/10/27 10:58:22 cegger Exp $");
 
 #include "opt_nfs_boot.h"
 #include "opt_inet.h"
@@ -103,7 +103,7 @@
  * is used for all subsequent booptaram RPCs.
  */
 int
-nfs_bootparam(struct nfs_diskless *nd, struct lwp *lwp)
+nfs_bootparam(struct nfs_diskless *nd, struct lwp *lwp, int *flags)
 {
 	struct ifnet *ifp = nd->nd_ifp;
 	struct in_addr my_ip, arps_ip, gw_ip;
@@ -141,9 +141,12 @@
 		goto out;
 	}
 
-	nd->nd_myip.s_addr = my_ip.s_addr;
-	printf("nfs_boot: client_addr=%s", inet_ntoa(my_ip));
-	printf(" (RARP from %s)\n", inet_ntoa(arps_ip));
+	if (!(*flags & NFS_BOOT_HAS_MYIP)) {
+		nd->nd_myip.s_addr = my_ip.s_addr;
+		printf("nfs_boot: client_addr=%s", inet_ntoa(my_ip));
+		printf(" (RARP from %s)\n", inet_ntoa(arps_ip));
+		*flags |= NFS_BOOT_HAS_MYIP;
+	}
 
 	/*
 	 * Do enough of ifconfig(8) so that the chosen interface
@@ -262,6 +265,9 @@
 	if (gw_ndm)
 		kmem_free(gw_ndm, sizeof(*gw_ndm));
 #endif
+	if ((*flags & NFS_BOOT_ALLINFO) != NFS_BOOT_ALLINFO)
+		return error ? error : EADDRNOTAVAIL;
+
 	return (error);
 }
 
--- a/sys/nfs/nfs_bootstatic.c	Mon Oct 27 08:27:04 2008 +0000
+++ b/sys/nfs/nfs_bootstatic.c	Mon Oct 27 10:58:22 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_bootstatic.c,v 1.5 2007/07/08 21:08:09 bouyer Exp $	*/
+/*	$NetBSD: nfs_bootstatic.c,v 1.6 2008/10/27 10:58:22 cegger Exp $	*/
 
 /*
  *
@@ -33,7 +33,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_bootstatic.c,v 1.5 2007/07/08 21:08:09 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_bootstatic.c,v 1.6 2008/10/27 10:58:22 cegger Exp $");
 
 #include "opt_nfs_boot.h"
 #include "opt_inet.h"
@@ -67,7 +67,7 @@
 int (*nfs_bootstatic_callback)(struct nfs_diskless *) = NULL;
 
 int
-nfs_bootstatic(struct nfs_diskless *nd, struct lwp *lwp)
+nfs_bootstatic(struct nfs_diskless *nd, struct lwp *lwp, int *_flags)
 {
 	struct ifnet *ifp = nd->nd_ifp;
 	struct sockaddr_in *sin;
@@ -78,55 +78,87 @@
 	else
 		flags = 0;
 
-	if (flags & NFS_BOOTSTATIC_NOSTATIC)
+	if (flags & NFS_BOOT_NOSTATIC)
 		return EOPNOTSUPP;
 
 	if (flags == 0) {
 #ifdef NFS_BOOTSTATIC_MYIP
-		nd->nd_myip.s_addr = inet_addr(NFS_BOOTSTATIC_MYIP);
-		flags |= NFS_BOOTSTATIC_HAS_MYIP;
+		if (!(*_flags & NFS_BOOT_HAS_MYIP)) {
+			nd->nd_myip.s_addr = inet_addr(NFS_BOOTSTATIC_MYIP);
+			flags |= NFS_BOOT_HAS_MYIP;
+		}
 #endif
 #ifdef NFS_BOOTSTATIC_GWIP
-		nd->nd_gwip.s_addr = inet_addr(NFS_BOOTSTATIC_GWIP);
-		flags |= NFS_BOOTSTATIC_HAS_GWIP;
+		if (!(*_flags & NFS_BOOT_HAS_GWIP)) {
+			nd->nd_gwip.s_addr = inet_addr(NFS_BOOTSTATIC_GWIP);
+			flags |= NFS_BOOT_HAS_GWIP;
+		}
 #endif
 #ifdef NFS_BOOTSTATIC_MASK
-		nd->nd_mask.s_addr = inet_addr(NFS_BOOTSTATIC_MASK);
-		flags |= NFS_BOOTSTATIC_HAS_MASK;
+		if (!(*_flags & NFS_BOOT_HAS_MASK)) {
+			nd->nd_mask.s_addr = inet_addr(NFS_BOOTSTATIC_MASK);
+			flags |= NFS_BOOT_HAS_MASK;
+		}
 #endif
 #ifdef NFS_BOOTSTATIC_SERVADDR
+		if (!(*_flags & NFS_BOOT_HAS_SERVADDR)) {
+			sin = (struct sockaddr_in *) &nd->nd_root.ndm_saddr;
+			memset((void *)sin, 0, sizeof(*sin));
+			sin->sin_len = sizeof(*sin);
+			sin->sin_family = AF_INET;
+			sin->sin_addr.s_addr = inet_addr(NFS_BOOTSTATIC_SERVADDR);
+			flags |= NFS_BOOT_HAS_SERVADDR;
+		}
+#endif
+#ifdef NFS_BOOTSTATIC_SERVER
+		if (!(*_flags & NFS_BOOT_HAS_SERVER)) {
+			strncpy(nd->nd_root.ndm_host, NFS_BOOTSTATIC_SERVER,
+				MNAMELEN);
+			flags |= NFS_BOOT_HAS_SERVER;
+			if (strchr(nd->nd_root.ndm_host, ':') != NULL)
+				flags |= NFS_BOOT_HAS_ROOTPATH;
+		}
+#endif
+	}
+
+	*_flags |= flags;
+
+	if (!(*_flags & NFS_BOOT_HAS_SERVADDR) && (*_flags & NFS_BOOT_HAS_SERVER)) {
+		char rootserver[MNAMELEN];
+		char *sep;
+
+		sep = strchr(nd->nd_root.ndm_host, ':');
+		strlcpy(rootserver, nd->nd_root.ndm_host,
+			sep - nd->nd_root.ndm_host+1);
+
 		sin = (struct sockaddr_in *) &nd->nd_root.ndm_saddr;
 		memset((void *)sin, 0, sizeof(*sin));
 		sin->sin_len = sizeof(*sin);
 		sin->sin_family = AF_INET;
-		sin->sin_addr.s_addr = inet_addr(NFS_BOOTSTATIC_SERVADDR);
-		flags |= NFS_BOOTSTATIC_HAS_SERVADDR;
-#endif
-#ifdef NFS_BOOTSTATIC_SERVER
-		strncpy(nd->nd_root.ndm_host, NFS_BOOTSTATIC_SERVER, MNAMELEN);
-		flags |= NFS_BOOTSTATIC_HAS_SERVER;
-#endif
+		sin->sin_addr.s_addr = inet_addr(rootserver);
+		flags |= NFS_BOOT_HAS_SERVADDR;
+		*_flags |= NFS_BOOT_HAS_SERVADDR;
 	}
 
-	if (flags & NFS_BOOTSTATIC_HAS_MYIP)
+	if (flags & NFS_BOOT_HAS_MYIP)
 		aprint_normal("nfs_boot: client_addr=%s\n",
 		    inet_ntoa(nd->nd_myip));
 
-	if (flags & NFS_BOOTSTATIC_HAS_GWIP)
+	if (flags & NFS_BOOT_HAS_GWIP)
 		aprint_normal("nfs_boot: gateway=%s\n",
 		    inet_ntoa(nd->nd_gwip));
 
-	if (flags & NFS_BOOTSTATIC_HAS_MASK)
+	if (flags & NFS_BOOT_HAS_MASK)
 		aprint_normal("nfs_boot: netmask=%s\n",
 		    inet_ntoa(nd->nd_mask));
 
-	if (flags & NFS_BOOTSTATIC_HAS_SERVADDR) {
+	if (flags & NFS_BOOT_HAS_SERVADDR) {
 		sin = (struct sockaddr_in *) &nd->nd_root.ndm_saddr;
 		aprint_normal("nfs_boot: server=%s\n",
 		    inet_ntoa(sin->sin_addr));
 	}
 
-	if (flags & NFS_BOOTSTATIC_HAS_SERVER)
+	if (flags & NFS_BOOT_HAS_SERVER)
 		aprint_normal("nfs_boot: root=%.*s\n", MNAMELEN,
 		    nd->nd_root.ndm_host);
 
@@ -135,14 +167,17 @@
 	 * can talk to the servers.
 	 */
 	error = nfs_boot_setaddress(ifp, lwp,
-	    flags & NFS_BOOTSTATIC_HAS_MYIP ? nd->nd_myip.s_addr : INADDR_ANY,
-	    flags & NFS_BOOTSTATIC_HAS_MASK ? nd->nd_mask.s_addr : INADDR_ANY,
+	    *_flags & NFS_BOOT_HAS_MYIP ? nd->nd_myip.s_addr : INADDR_ANY,
+	    *_flags & NFS_BOOT_HAS_MASK ? nd->nd_mask.s_addr : INADDR_ANY,
 	    INADDR_ANY);
 	if (error) {
 		aprint_error("nfs_boot: set ifaddr, error=%d\n", error);
 		goto out;
 	}
 
+	if ((*_flags & NFS_BOOT_ALLINFO) != NFS_BOOT_ALLINFO)
+		return EADDRNOTAVAIL;
+
 	error = 0;
 
  out:
--- a/sys/nfs/nfsdiskless.h	Mon Oct 27 08:27:04 2008 +0000
+++ b/sys/nfs/nfsdiskless.h	Mon Oct 27 10:58:22 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfsdiskless.h,v 1.28 2008/10/24 17:17:12 cegger Exp $	*/
+/*	$NetBSD: nfsdiskless.h,v 1.29 2008/10/27 10:58:23 cegger Exp $	*/
 
 /*-
  * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@@ -80,18 +80,22 @@
 			   int (*)(struct mbuf*, void*), struct mbuf**,
 			   struct mbuf**, void*, struct lwp *);
 
-int nfs_bootdhcp  (struct nfs_diskless *, struct lwp *);
-int nfs_bootparam (struct nfs_diskless *, struct lwp *);
-int nfs_bootstatic (struct nfs_diskless *, struct lwp *);
+int nfs_bootdhcp  (struct nfs_diskless *, struct lwp *, int *);
+int nfs_bootparam (struct nfs_diskless *, struct lwp *, int *);
+int nfs_bootstatic (struct nfs_diskless *, struct lwp *, int *);
 
 extern int (*nfs_bootstatic_callback)(struct nfs_diskless *);
 
-#define	NFS_BOOTSTATIC_HAS_MYIP		0x01
-#define	NFS_BOOTSTATIC_HAS_GWIP		0x02
-#define	NFS_BOOTSTATIC_HAS_MASK		0x04
-#define	NFS_BOOTSTATIC_HAS_SERVADDR	0x08
-#define	NFS_BOOTSTATIC_HAS_SERVER	0x10
-#define	NFS_BOOTSTATIC_NOSTATIC		0x20
+#define NFS_BOOT_HAS_MYIP	0x01
+#define NFS_BOOT_HAS_GWIP	0x02
+#define NFS_BOOT_HAS_MASK	0x04
+#define NFS_BOOT_HAS_SERVADDR	0x08
+#define NFS_BOOT_HAS_SERVER	0x10
+#define NFS_BOOT_NOSTATIC	0x20
+#define NFS_BOOT_HAS_ROOTPATH	0x40
+
+#define NFS_BOOT_ALLINFO	(NFS_BOOT_HAS_MYIP|NFS_BOOT_HAS_GWIP|NFS_BOOT_HAS_MASK|NFS_BOOT_HAS_SERVADDR|NFS_BOOT_HAS_SERVER|NFS_BOOT_HAS_ROOTPATH)
+
 #endif /* _KERNEL */
 
 #endif /* _NFS_NFSDISKLESS_H_ */