Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148277193
D22487.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
24 KB
Referenced Files
None
Subscribers
None
D22487.diff
View Options
Index: sys/fs/nfsclient/nfs_clvfsops.c
===================================================================
--- sys/fs/nfsclient/nfs_clvfsops.c
+++ sys/fs/nfsclient/nfs_clvfsops.c
@@ -40,6 +40,8 @@
#include "opt_bootp.h"
#include "opt_nfsroot.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -161,8 +163,8 @@
* isn't used in that case.
*/
#if !defined(NFS_ROOT)
-struct nfs_diskless nfs_diskless = { { { 0 } } };
-struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
+struct nfs_diskless nfs_diskless = { AF_UNSPEC, NULL, { { 0 } } };
+struct nfsv3_diskless nfsv3_diskless = { AF_UNSPEC, NULL, { { 0 } } };
int nfs_diskless_valid = 0;
#endif
@@ -173,14 +175,14 @@
SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
+/* XXX-BZ unused and not correct anymore. */
SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
&nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr),
"%Ssockaddr_in", "Diskless root nfs address");
void newnfsargs_ntoh(struct nfs_args *);
-static int nfs_mountdiskless(char *,
- struct sockaddr_in *, struct nfs_args *,
+static int nfs_mountdiskless(struct nfsv3_diskless *nd,
struct thread *, struct vnode **, struct mount *);
static void nfs_convert_diskless(void);
static void nfs_convert_oargs(struct nfs_args *args,
@@ -254,10 +256,33 @@
nfs_convert_diskless(void)
{
- bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
- sizeof(struct ifaliasreq));
- bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
- sizeof(struct sockaddr_in));
+ switch (nfs_diskless.sa_family) {
+#ifdef INET
+ case PF_INET:
+ bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
+ sizeof(struct ifaliasreq));
+ bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
+ sizeof(struct sockaddr_in));
+ bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
+ sizeof(struct sockaddr_in));
+ break;
+#endif
+#ifdef INET6
+ case PF_INET6:
+ bcopy(&nfs_diskless.myif6, &nfsv3_diskless.myif6,
+ sizeof(nfs_diskless.myif6));
+ bcopy(&nfs_diskless.mygateway6, &nfsv3_diskless.mygateway6,
+ sizeof(nfs_diskless.mygateway6));
+ bcopy(&nfs_diskless.root_saddr6,&nfsv3_diskless.root_saddr6,
+ sizeof(nfs_diskless.root_saddr6));
+ break;
+#endif
+ default:
+ panic("%s: are you trying to trick me? sa_family %u\n",
+ __func__, nfs_diskless._mygateway.sa.sa_family);
+ }
+ nfsv3_diskless.sa_family = nfs_diskless.sa_family;
+ nfsv3_diskless.ifp = nfs_diskless.ifp;
nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
nfsv3_diskless.root_fhsize = NFSX_MYFH;
@@ -266,8 +291,6 @@
nfsv3_diskless.root_fhsize = NFSX_V2FH;
bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
}
- bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
- sizeof(struct sockaddr_in));
bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
nfsv3_diskless.root_time = nfs_diskless.root_time;
bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
@@ -403,9 +426,7 @@
struct vnode *vp;
struct ifreq ir;
int error;
- u_long l;
- char buf[128];
- char *cp;
+ char *afstr, *cp;
#if defined(BOOTP_NFSROOT) && defined(BOOTP)
bootpc_init(); /* use bootp to get nfs_diskless filled in */
@@ -422,38 +443,37 @@
* Do enough of ifconfig(8) so that the critical net interface can
* talk to the server.
*/
- error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
+ error = socreate(nd->sa_family, &so, nd->root_args.sotype, 0,
td->td_ucred, td);
if (error)
- panic("nfs_mountroot: socreate(%04x): %d",
- nd->myif.ifra_addr.sa_family, error);
+ panic("%s: socreate(%04x): %d", __func__, nd->sa_family, error);
-#if 0 /* XXX Bad idea */
- /*
- * We might not have been told the right interface, so we pass
- * over the first ten interfaces of the same kind, until we get
- * one of them configured.
- */
-
- for (i = strlen(nd->myif.ifra_name) - 1;
- nd->myif.ifra_name[i] >= '0' &&
- nd->myif.ifra_name[i] <= '9';
- nd->myif.ifra_name[i] ++) {
+ afstr = "";
+ switch (nd->sa_family) {
+#ifdef INET
+ case PF_INET:
error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
- if(!error)
- break;
- }
+ break;
#endif
- error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
+#ifdef INET6
+ case PF_INET6:
+ error = ifioctl(so, SIOCAIFADDR_IN6, (caddr_t)&nd->myif6, td);
+ afstr = "_IN6";
+ break;
+#endif
+ default:
+ error = EPFNOSUPPORT;
+ break;
+ }
if (error)
- panic("nfs_mountroot: SIOCAIFADDR: %d", error);
+ panic("%s: SIOCAIFADDR%s: %d", __func__, afstr, error);
if ((cp = kern_getenv("boot.netif.mtu")) != NULL) {
ir.ifr_mtu = strtol(cp, NULL, 10);
bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
freeenv(cp);
error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
if (error)
- printf("nfs_mountroot: SIOCSIFMTU: %d", error);
+ printf("%s: SIOCSIFMTU: %d", __func__, error);
}
soclose(so);
@@ -463,7 +483,8 @@
* is not set by the DHCP server. Check also for a value of 0
* to avoid panicking inappropriately in that situation.
*/
- if (nd->mygateway.sin_len != 0 &&
+#ifdef INET
+ if (nd->sa_family == PF_INET && nd->mygateway.sin_len != 0 &&
nd->mygateway.sin_addr.s_addr != 0) {
struct sockaddr_in mask, sin;
@@ -479,22 +500,37 @@
RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
CURVNET_RESTORE();
if (error)
- panic("nfs_mountroot: RTM_ADD: %d", error);
+ panic("%s: RTM_ADD: %d", __func__, error);
}
+#endif
+#ifdef INET6
+ if (nd->sa_family == PF_INET6 && nd->mygateway6.sin6_len != 0 &&
+ !IN6_IS_ADDR_UNSPECIFIED(&nd->mygateway6.sin6_addr)) {
+ struct sockaddr_in6 sin6, mask;
+ bzero(&sin6, sizeof(sin6));
+ bzero(&mask, sizeof(mask));
+ sin6.sin6_family = PF_INET6;
+ sin6.sin6_len = mask.sin6_len = sizeof(mask);
+ /* XXX MRT use table 0 for this sort of thing */
+ CURVNET_SET(TD_TO_VNET(td));
+ error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&sin6,
+ (struct sockaddr *)&nd->mygateway6,
+ (struct sockaddr *)&mask,
+ RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
+ CURVNET_RESTORE();
+ if (error)
+ panic("%s: RTM_ADD: %d", __func__, error);
+
+ }
+#endif
+
/*
* Create the rootfs mount point.
*/
nd->root_args.fh = nd->root_fh;
nd->root_args.fhsize = nd->root_fhsize;
- l = ntohl(nd->root_saddr.sin_addr.s_addr);
- snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
- (l >> 24) & 0xff, (l >> 16) & 0xff,
- (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam);
- printf("NFS ROOT: %s\n", buf);
- nd->root_args.hostname = buf;
- if ((error = nfs_mountdiskless(buf,
- &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
+ if ((error = nfs_mountdiskless(nd, td, &vp, mp)) != 0) {
return (error);
}
@@ -515,28 +551,77 @@
* Internal version of mount system call for diskless setup.
*/
static int
-nfs_mountdiskless(char *path,
- struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
- struct vnode **vpp, struct mount *mp)
+nfs_mountdiskless(struct nfsv3_diskless *nd,
+ struct thread *td, struct vnode **vpp, struct mount *mp)
{
+#ifdef INET6
+ char sname6[INET6_ADDRSTRLEN];
+ struct sockaddr_in6 *sin6;
+#endif
+#ifdef INET
+ char sname[INET_ADDRSTRLEN];
+ struct sockaddr_in *sin;
+#endif
struct sockaddr *nam;
int dirlen, error;
+ char buf[128];
char *dirpath;
+ switch (nd->sa_family) {
+#ifdef INET
+ case PF_INET:
+ sin = &nd->root_saddr;
+ inet_ntop(PF_INET, &sin->sin_addr, sname, sizeof(sname));
+ snprintf(buf, sizeof(buf), "%s:%s", sname, nd->root_hostnam);
+ nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
+ break;
+#endif
+#ifdef INET6
+ case PF_INET6:
+ sin6 = &nd->root_saddr6;
+ inet_ntop(PF_INET6, &sin6->sin6_addr, sname6, sizeof(sname6));
+ snprintf(buf, sizeof(buf), "[%s]:%s", sname6, nd->root_hostnam);
+ nam = sodupsockaddr((struct sockaddr *)sin6, M_WAITOK);
+ break;
+#endif
+ default:
+ printf(buf, sizeof(buf),
+ "%s: IP support in your config is:/nonexistent", __func__);
+ return (EPFNOSUPPORT);
+ }
+
+ printf("NFS ROOT: %s\n", buf);
+ nd->root_args.hostname = buf;
+
/*
* Find the directory path in "path", which also has the server's
* name/ip address in it.
*/
- dirpath = strchr(path, ':');
+ dirpath = nd->root_hostnam;
if (dirpath != NULL)
- dirlen = strlen(++dirpath);
+ dirlen = strlen(dirpath);
else
dirlen = 0;
- nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
- if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
- NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
+
+ if (nd->ifp != NULL && nd->ifp->if_link_state != LINK_STATE_UP) {
+ if (bootverbose)
+ printf("%s: waiting for link up..\n", __func__);
+ for (error = 0; nd->ifp != NULL && error < 10; error++) {
+ if (nd->ifp->if_link_state == LINK_STATE_UP) {
+ break;
+ }
+ pause("nfslink", hz);
+ }
+ if (bootverbose)
+ printf("%s: link %s\n", __func__,
+ (nd->ifp->if_link_state == LINK_STATE_UP) ?
+ "UP" : "DOWN");
+ }
+
+ if ((error = mountnfs(&nd->root_args, mp, nam, buf, NULL, 0, dirpath,
+ dirlen, NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
NFS_DEFAULT_NEGNAMETIMEO, 0)) != 0) {
- printf("nfs_mountroot: mount %s on /: %d\n", path, error);
+ printf("%s: mount %s on /: %d\n", __func__, buf, error);
return (error);
}
return (0);
@@ -829,7 +914,7 @@
/*
* XXX: hardcoded port number.
*/
- sin->sin_port = htons(2049);
+ sin->sin_port = htons(NFS_PORT);
*hostnamep = strdup(nam, M_NEWNFSMNT);
*sinp = sin;
Index: sys/nfs/nfs_diskless.c
===================================================================
--- sys/nfs/nfs_diskless.c
+++ sys/nfs/nfs_diskless.c
@@ -38,6 +38,8 @@
__FBSDID("$FreeBSD$");
#include "opt_bootp.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -54,14 +56,27 @@
#include <net/ethernet.h>
#include <net/vnet.h>
+#if defined(INET6) || defined(INET)
#include <netinet/in.h>
+#endif
+#if defined(INET6)
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+#endif
+
#include <nfs/nfsproto.h>
#include <nfsclient/nfs.h>
#include <nfs/nfsdiskless.h>
#define NFS_IFACE_TIMEOUT_SECS 10 /* Timeout for interface to appear. */
+#ifdef INET
static int inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa);
+#endif
+#ifdef INET6
+static int in6addr_to_sockaddr(char *ev, struct sockaddr_in6 *sin6,
+ struct sockaddr_in6 *in6mask);
+#endif
static int hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa);
static int decode_nfshandle(char *ev, u_char *fh, int maxfh);
@@ -70,8 +85,8 @@
* server for a diskless/dataless machine. It is initialized below just
* to ensure that it is allocated to initialized data (.data not .bss).
*/
-struct nfs_diskless nfs_diskless = { { { 0 } } };
-struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
+struct nfs_diskless nfs_diskless = { AF_UNSPEC, NULL, { { 0 } } };
+struct nfsv3_diskless nfsv3_diskless = { AF_UNSPEC, NULL, { { 0 } } };
int nfs_diskless_valid = 0;
/*
@@ -146,18 +161,52 @@
free(opts, M_TEMP);
}
+#ifdef INET6
+static void
+setup_myif6(struct in6_aliasreq *ifr,
+ struct sockaddr_in6 *sin6, struct sockaddr_in6 *mask)
+{
+
+ bcopy(sin6, &ifr->ifra_addr, sizeof(*sin6));
+ /* ifra_dstaddr */
+ bcopy(mask, &ifr->ifra_prefixmask, sizeof(*mask));
+ ifr->ifra_flags = 0;
+ ifr->ifra_lifetime.ia6t_expire = 0;
+ ifr->ifra_lifetime.ia6t_preferred = 0;
+ ifr->ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+ ifr->ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
+}
+#endif
+
+#ifdef INET
+static void
+setup_myif(struct ifaliasreq *ifr,
+ struct sockaddr_in *sin, struct sockaddr_in *netmask)
+{
+
+ bcopy(sin, &ifr->ifra_addr, sizeof(*sin));
+ bcopy(sin, &ifr->ifra_broadaddr, sizeof(*sin));
+ ((struct sockaddr_in *)&ifr->ifra_broadaddr)->sin_addr.s_addr =
+ sin->sin_addr.s_addr | ~ netmask->sin_addr.s_addr;
+ bcopy(netmask, &ifr->ifra_mask, sizeof(*netmask));
+}
+#endif
+
/*
* Populate the essential fields in the nfsv3_diskless structure.
*
* The loader is expected to export the following environment variables:
*
* boot.netif.name name of boot interface
- * boot.netif.ip IP address on boot interface
- * boot.netif.netmask netmask on boot interface
- * boot.netif.gateway default gateway (optional)
+ * boot.netif.ip IPv4 address on boot interface
+ * boot.netif.netmask IPv4 netmask on boot interface
+ * boot.netif.gateway IPv4 default gateway (optional)
+ * boot.netif.ip6 IPv6 address on boot interface
+ * boot.netif.gateway6 IPv6 default gateway (optional)
* boot.netif.hwaddr hardware address of boot interface
* boot.netif.mtu interface mtu from bootp/dhcp (optional)
- * boot.nfsroot.server IP address of root filesystem server
+ * boot.nfsroot.server IPv4 address of root filesystem server
+ * boot.nfsroot.server6 IPv6 address of root filesystem server
* boot.nfsroot.path path of the root filesystem on server
* boot.nfsroot.nfshandle NFS handle for root filesystem on server
* boot.nfsroot.nfshandlelen and length of this handle (for NFSv3 only)
@@ -171,7 +220,14 @@
struct ifnet *ifp;
struct ifaddr *ifa;
struct sockaddr_dl *sdl, ourdl;
- struct sockaddr_in myaddr, netmask;
+#ifdef INET
+ struct sockaddr_in sin, netmask;
+ bool ipv4;
+#endif
+#ifdef INET6
+ struct sockaddr_in6 sin6, in6mask;
+ bool ipv6;
+#endif
char *cp;
int cnt, fhlen, is_nfsv3;
uint32_t len;
@@ -180,43 +236,88 @@
if (nfs_diskless_valid != 0)
return;
+#if !defined(INET6) && !defined(INET)
+ printf("%s failing: neither INET nor INET6 support.\n", __func__);
+ return;
+#endif
+
/* get handle size. If this succeeds, it's an NFSv3 setup. */
if ((cp = kern_getenv("boot.nfsroot.nfshandlelen")) != NULL) {
cnt = sscanf(cp, "%d", &len);
freeenv(cp);
if (cnt != 1 || len == 0 || len > NFSX_V3FHMAX) {
- printf("nfs_diskless: bad NFS handle len\n");
+ printf("%s: bad NFS handle len\n", __func__);
return;
}
nd3->root_fhsize = len;
is_nfsv3 = 1;
} else
is_nfsv3 = 0;
- /* set up interface */
- if (inaddr_to_sockaddr("boot.netif.ip", &myaddr))
- return;
- if (inaddr_to_sockaddr("boot.netif.netmask", &netmask)) {
- printf("nfs_diskless: no netmask\n");
- return;
+ /*
+ * Set up interface.
+ * For now assume that v4 and v6 addresses are stored
+ * in different env. variables from loader. Prefer v6 if
+ * available. Trying a fallback to a 2nd choice is hard in this
+ * NFS code. If you want v4 do not set v6.
+ */
+#ifdef INET6
+ ipv6 = true;
+ if (ipv6 && in6addr_to_sockaddr("boot.netif.ip6", &sin6, &in6mask)) {
+ if (bootverbose)
+ printf("%s: skipping IPv6, no prefix.\n", __func__);
+ ipv6 = false;
}
+#endif
+#ifdef INET
+ ipv4 = true;
+ if (ipv4 && inaddr_to_sockaddr("boot.netif.ip", &sin)) {
+ if (bootverbose)
+ printf("%s: skipping IPv4, no address.\n", __func__);
+ ipv4 = false;
+ }
+ if (ipv4 && inaddr_to_sockaddr("boot.netif.netmask", &netmask)) {
+ if (bootverbose)
+ printf("%s: skipping IPv4, no netmask.\n", __func__);
+ ipv4 = false;
+ }
+#endif
+
if (is_nfsv3 != 0) {
- bcopy(&myaddr, &nd3->myif.ifra_addr, sizeof(myaddr));
- bcopy(&myaddr, &nd3->myif.ifra_broadaddr, sizeof(myaddr));
- ((struct sockaddr_in *)
- &nd3->myif.ifra_broadaddr)->sin_addr.s_addr =
- myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
- bcopy(&netmask, &nd3->myif.ifra_mask, sizeof(netmask));
+#ifdef INET6
+ if (ipv6) {
+ nd3->sa_family = AF_INET6;
+ setup_myif6(&nd3->myif6, &sin6, &in6mask);
+ }
+#endif
+#if defined(INET6) && defined(INET)
+ else
+#endif
+#ifdef INET
+ if (ipv4) {
+ nd3->sa_family = AF_INET;
+ setup_myif(&nd3->myif, &sin, &netmask);
+ }
+#endif
} else {
- bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr));
- bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr));
- ((struct sockaddr_in *)
- &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
- myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
- bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask));
+#ifdef INET6
+ if (ipv6) {
+ nd->sa_family = AF_INET6;
+ setup_myif6(&nd->myif6, &sin6, &in6mask);
+ }
+#endif
+#if defined(INET6) && defined(INET)
+ else
+#endif
+#ifdef INET
+ if (ipv4) {
+ nd->sa_family = AF_INET;
+ setup_myif(&nd->myif, &sin, &netmask);
+ }
+#endif
}
if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) {
- printf("nfs_diskless: no hardware address\n");
+ printf("%s aborting: no hardware address\n", __func__);
return;
}
ifa = NULL;
@@ -246,37 +347,58 @@
pause("nfssdl", hz / 5);
goto retry;
}
- printf("nfs_diskless: no interface\n");
+ printf("%s: no interface\n", __func__);
return; /* no matching interface */
match_done:
kern_setenv("boot.netif.name", ifp->if_xname);
- if (is_nfsv3 != 0) {
- strlcpy(nd3->myif.ifra_name, ifp->if_xname,
- sizeof(nd3->myif.ifra_name));
-
- /* set up gateway */
- inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway);
+ if (is_nfsv3 != 0) {
+ nd3->ifp = ifp; /* XXX-BZ this is a dangerous game; ref it! */
+#ifdef INET6
+ if (ipv6) {
+ strlcpy(nd3->myif6.ifra_name, ifp->if_xname,
+ sizeof(nd3->myif6.ifra_name));
+ if (in6addr_to_sockaddr("boot.nfsroot.server6",
+ &nd3->root_saddr6, NULL)) {
+ printf("%s: no IPv6 server\n", __func__);
+ return;
+ }
+ nd3->root_saddr6.sin6_port = htons(NFS_PORT);
+ in6addr_to_sockaddr("boot.netif.gateway6",
+ &nd3->mygateway6, NULL);
+ }
+#endif
+#if defined(INET6) && defined(INET)
+ else
+#endif
+#ifdef INET
+ if (ipv4) {
+ strlcpy(nd3->myif.ifra_name, ifp->if_xname,
+ sizeof(nd3->myif.ifra_name));
+ if (inaddr_to_sockaddr("boot.nfsroot.server",
+ &nd3->root_saddr)) {
+ printf("%s: no IPv4 server\n", __func__);
+ return;
+ }
+ nd3->root_saddr.sin_port = htons(NFS_PORT);
+ inaddr_to_sockaddr("boot.netif.gateway",
+ &nd3->mygateway);
+ }
+#endif
/* set up root mount */
nd3->root_args.rsize = 32768; /* XXX tunable? */
nd3->root_args.wsize = 32768;
nd3->root_args.sotype = SOCK_STREAM;
nd3->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE |
NFSMNT_RSIZE | NFSMNT_RESVPORT);
- if (inaddr_to_sockaddr("boot.nfsroot.server",
- &nd3->root_saddr)) {
- printf("nfs_diskless: no server\n");
- return;
- }
- nd3->root_saddr.sin_port = htons(NFS_PORT);
fhlen = decode_nfshandle("boot.nfsroot.nfshandle",
&nd3->root_fh[0], NFSX_V3FHMAX);
if (fhlen == 0) {
- printf("nfs_diskless: no NFS handle\n");
+ printf("%s: no NFS handle\n", __func__);
return;
}
if (fhlen != nd3->root_fhsize) {
- printf("nfs_diskless: bad NFS handle len=%d\n", fhlen);
+ printf("%s: bad NFS handle len=%d\n", __func__, fhlen);
return;
}
if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) {
@@ -290,27 +412,48 @@
nfs_diskless_valid = 3;
} else {
- strlcpy(nd->myif.ifra_name, ifp->if_xname,
- sizeof(nd->myif.ifra_name));
-
- /* set up gateway */
- inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway);
-
+ nd->ifp = ifp;
+#ifdef INET6
+ if (ipv6) {
+ strlcpy(nd->myif6.ifra_name, ifp->if_xname,
+ sizeof(nd->myif6.ifra_name));
+ if (in6addr_to_sockaddr("boot.nfsroot.server6",
+ &nd->root_saddr6, NULL)) {
+ printf("%s: no IPv6 server\n", __func__);
+ return;
+ }
+ nd->root_saddr6.sin6_port = htons(NFS_PORT);
+ in6addr_to_sockaddr("boot.netif.gateway6",
+ &nd->mygateway6, NULL);
+ }
+#endif
+#if defined(INET6) && defined(INET)
+ else
+#endif
+#ifdef INET
+ if (ipv4) {
+ strlcpy(nd->myif.ifra_name, ifp->if_xname,
+ sizeof(nd->myif.ifra_name));
+ if (inaddr_to_sockaddr("boot.nfsroot.server",
+ &nd->root_saddr)) {
+ printf("%s: no IPv4 server\n", __func__);
+ return;
+ }
+ nd->root_saddr.sin_port = htons(NFS_PORT);
+ inaddr_to_sockaddr("boot.netif.gateway",
+ &nd->mygateway);
+ }
+#endif
/* set up root mount */
nd->root_args.rsize = 8192; /* XXX tunable? */
nd->root_args.wsize = 8192;
nd->root_args.sotype = SOCK_STREAM;
nd->root_args.flags = (NFSMNT_WSIZE |
NFSMNT_RSIZE | NFSMNT_RESVPORT);
- if (inaddr_to_sockaddr("boot.nfsroot.server",
- &nd->root_saddr)) {
- printf("nfs_diskless: no server\n");
- return;
- }
- nd->root_saddr.sin_port = htons(NFS_PORT);
+
if (decode_nfshandle("boot.nfsroot.nfshandle",
&nd->root_fh[0], NFSX_V2FH) == 0) {
- printf("nfs_diskless: no NFS handle\n");
+ printf("%s: no NFS handle\n", __func__);
return;
}
if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) {
@@ -340,27 +483,85 @@
}
}
+#ifdef INET
static int
-inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa)
+inaddr_to_sockaddr(char *ev, struct sockaddr_in *sin)
{
- u_int32_t a[4];
char *cp;
- int count;
+ int rc;
- bzero(sa, sizeof(*sa));
- sa->sin_len = sizeof(*sa);
- sa->sin_family = AF_INET;
+ bzero(sin, sizeof(*sin));
+ sin->sin_len = sizeof(*sin);
+ sin->sin_family = AF_INET;
if ((cp = kern_getenv(ev)) == NULL)
return (1);
- count = sscanf(cp, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
+ rc = inet_pton(AF_INET, cp, &sin->sin_addr);
freeenv(cp);
- if (count != 4)
+ if (rc != 1)
return (1);
- sa->sin_addr.s_addr =
- htonl((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);
return (0);
}
+#endif
+
+#ifdef INET6
+static int
+in6addr_to_sockaddr(char *ev, struct sockaddr_in6 *sin6,
+ struct sockaddr_in6 *in6mask)
+{
+ char *cp, *p, *pend;
+ unsigned long l;
+ int rc;
+
+ bzero(sin6, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(*sin6);
+
+ if ((cp = kern_getenv(ev)) == NULL)
+ return (1);
+
+ p = strchr(cp, '/');
+ if (p != NULL)
+ *p++ = '\0';
+ rc = inet_pton(AF_INET6, cp, &sin6->sin6_addr);
+ if (rc != 1) {
+ freeenv(cp);
+ return (1);
+ }
+
+ if (in6mask != NULL) {
+ /*
+ * Try to convert the /prefix into something we can
+ * use as a mask.
+ */
+ bzero(in6mask, sizeof(*in6mask));
+ /* We do not set faimly for the mask? */
+ in6mask->sin6_len = sizeof(*in6mask);
+ if (p != NULL && *p != '\0') {
+ l = strtoul(p, &pend, 0);
+ if (l == ULONG_MAX || (l == 0 && pend == p)) {
+ freeenv(cp);
+ return (1);
+ }
+ /* If l > 128, input error, use /64. */
+ if (l > 128)
+ in6mask->sin6_addr = in6mask64;
+ else if (l == 0 || l == 128)
+ in6mask->sin6_addr = in6mask128;
+ else {
+ for (p = (u_char *)&in6mask->sin6_addr; l > 7;
+ l -= 8)
+ *p++ = 0xff;
+ *p = 0xff << (8 - l);
+ }
+ } else
+ in6mask->sin6_addr = in6mask64;
+ }
+ freeenv(cp);
+
+ return (0);
+}
+#endif
static int
hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa)
Index: sys/nfs/nfsdiskless.h
===================================================================
--- sys/nfs/nfsdiskless.h
+++ sys/nfs/nfsdiskless.h
@@ -38,7 +38,19 @@
#ifndef _NFSCLIENT_NFSDISKLESS_H_
#define _NFSCLIENT_NFSDISKLESS_H_
+#ifndef _SOCKADDR_UNION_DEFINED
+#define _SOCKADDR_UNION_DEFINED
/*
+ * The union of all possible address formats we handle.
+ */
+union sockaddr_union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+#endif /* _SOCKADDR_UNION_DEFINED */
+
+/*
* Structure that must be initialized for a diskless nfs client.
* This structure is used by nfs_mountroot() to set up the root vnode,
* and to do a partial ifconfig(8) and route(8) so that the critical net
@@ -59,16 +71,27 @@
* still Version 2 anyhow.)
*/
struct nfsv3_diskless {
- struct ifaliasreq myif; /* Default interface */
- struct sockaddr_in mygateway; /* Default gateway */
+ sa_family_t sa_family;
+ struct ifnet *ifp;
+ union {
+ struct ifaliasreq _myif; /* Default interface */
+ struct in6_aliasreq _myif6;
+ } _lif;
+ union sockaddr_union _mygateway; /* Default gateway */
struct nfs_args root_args; /* Mount args for root fs */
int root_fhsize; /* Size of root file handle */
u_char root_fh[NFSX_V3FHMAX]; /* File handle of root dir */
- struct sockaddr_in root_saddr; /* Address of root server */
+ union sockaddr_union _root_saddr; /* Address of root server */
char root_hostnam[MNAMELEN]; /* Host name for mount pt */
long root_time; /* Timestamp of root fs */
char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */
};
+#define myif _lif._myif
+#define myif6 _lif._myif6
+#define mygateway _mygateway.sin
+#define mygateway6 _mygateway.sin6
+#define root_saddr _root_saddr.sin
+#define root_saddr6 _root_saddr.sin6
/*
* Old arguments to mount NFS
@@ -94,11 +117,16 @@
};
struct nfs_diskless {
- struct ifaliasreq myif; /* Default interface */
- struct sockaddr_in mygateway; /* Default gateway */
+ sa_family_t sa_family;
+ struct ifnet *ifp;
+ union {
+ struct ifaliasreq _myif; /* Default interface */
+ struct in6_aliasreq _myif6;
+ } _lif;
+ union sockaddr_union _mygateway; /* Default gateway */
struct onfs_args root_args; /* Mount args for root fs */
u_char root_fh[NFSX_V2FH]; /* File handle of root dir */
- struct sockaddr_in root_saddr; /* Address of root server */
+ union sockaddr_union _root_saddr; /* Address of root server */
char root_hostnam[MNAMELEN]; /* Host name for mount pt */
long root_time; /* Timestamp of root fs */
char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Mar 17, 11:13 PM (10 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29858077
Default Alt Text
D22487.diff (24 KB)
Attached To
Mode
D22487: [WIP] Add IPv6 NFS Root support
Attached
Detach File
Event Timeline
Log In to Comment