4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
30 * This program does the following:
33 * 0 - if the program successfully determined the net strategy.
34 * !0 - if an error occurred.
36 * b) If the program is successful, it prints three tokens to
37 * stdout: <root fs type> <interface name> <net config strategy>.
39 * <root fs type> - "nfs", "ufs" or "zfs"
40 * <interface name> - "hme0" or "none"
41 * <net config strategy> - "dhcp", "rarp", "bootprops"
48 * <root fs type> identifies the system's root file system type.
50 * <interface name> is the 16 char name of the root interface, and is only
51 * set if rarp/dhcp was used to configure the interface.
53 * <net config strategy> can be either "rarp", "dhcp", "bootprops", or
54 * "none" depending on which strategy was used to configure the
55 * interface. Is "none" if no interface was configured using a
58 * CAVEATS: what about autoclient systems? XXX
60 * The logic here must match that in usr/src/uts/common/fs/nfs/nfs_dlinet.c,
61 * in particular that code (which implements diskless boot) imposes an
62 * ordering on possible ways of configuring network interfaces.
69 #include <sys/types.h>
72 #include <sys/systeminfo.h>
73 #include <sys/socket.h>
74 #include <sys/sockio.h>
76 #include <sys/statvfs.h>
77 #include <libdevinfo.h>
81 static int s4
, s6
; /* inet and inet6 sockets */
86 if ((s4
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
87 (void) fprintf(stderr
, "%s: inet socket: %s\n", program
,
91 if ((s6
= socket(AF_INET6
, SOCK_DGRAM
, 0)) == -1) {
92 (void) fprintf(stderr
, "%s: inet6 socket: %s\n", program
,
109 static struct statvfs vfs
;
112 if (statvfs("/", &vfs
) < 0) {
115 if (strncmp(vfs
.f_basetype
, "nfs", sizeof ("nfs") - 1) == 0)
116 vfs
.f_basetype
[sizeof ("nfs") - 1] = '\0';
117 return (vfs
.f_basetype
);
122 * The following boot properties can be used to configure a network
123 * interface in the case of a diskless boot.
124 * host-ip, subnet-mask, server-path, server-name, server-ip.
126 * XXX non-diskless case requires "network-interface"?
129 boot_properties_present()
131 /* XXX should use sys/bootprops.h, but it's not delivered */
132 const char *required_properties
[] = {
140 const char **prop
= required_properties
;
144 if ((dn
= di_init("/", DINFOPROP
)) == DI_NODE_NIL
) {
145 (void) fprintf(stderr
, "%s: di_init: %s\n", program
,
151 while (*prop
!= NULL
) {
152 if (di_prop_lookup_strings(DDI_DEV_T_ANY
,
153 dn
, *prop
, &prop_value
) != 1) {
165 get_first_interface(boolean_t
*dhcpflag
)
168 struct lifconf ifconf
;
170 static char interface
[LIFNAMSIZ
];
171 boolean_t isv4
, found_one
= B_FALSE
;
173 ifnum
.lifn_family
= AF_UNSPEC
;
174 ifnum
.lifn_flags
= 0;
175 ifnum
.lifn_count
= 0;
177 if (ioctl(s4
, SIOCGLIFNUM
, &ifnum
) < 0) {
178 (void) fprintf(stderr
, "%s: SIOCGLIFNUM: %s\n", program
,
183 ifconf
.lifc_family
= AF_UNSPEC
;
184 ifconf
.lifc_flags
= 0;
185 ifconf
.lifc_len
= ifnum
.lifn_count
* sizeof (struct lifreq
);
186 ifconf
.lifc_buf
= alloca(ifconf
.lifc_len
);
188 if (ioctl(s4
, SIOCGLIFCONF
, &ifconf
) < 0) {
189 (void) fprintf(stderr
, "%s: SIOCGLIFCONF: %s\n", program
,
194 for (ifr
= ifconf
.lifc_req
; ifr
< &ifconf
.lifc_req
[ifconf
.lifc_len
/
195 sizeof (ifconf
.lifc_req
[0])]; ifr
++) {
197 struct sockaddr_in
*sin
;
199 if (strchr(ifr
->lifr_name
, ':') != NULL
)
200 continue; /* skip logical interfaces */
202 isv4
= ifr
->lifr_addr
.ss_family
== AF_INET
;
204 (void) strncpy(flifr
.lifr_name
, ifr
->lifr_name
, LIFNAMSIZ
);
206 if (ioctl(isv4
? s4
: s6
, SIOCGLIFFLAGS
, &flifr
) < 0) {
207 (void) fprintf(stderr
, "%s: SIOCGLIFFLAGS: %s\n",
208 program
, strerror(errno
));
212 if (!(flifr
.lifr_flags
& IFF_UP
) ||
213 (flifr
.lifr_flags
& (IFF_VIRTUAL
|IFF_POINTOPOINT
)))
217 * For the "nfs rarp" and "nfs bootprops"
218 * cases, we assume that the first non-virtual
219 * IFF_UP interface with a non-zero address is
222 * For the non-zero address check, we only check
223 * v4 interfaces, as it's not possible to set the
224 * the first logical interface (the only ones we
225 * look at here) to ::0; that interface must have
226 * a link-local address.
228 * If we don't find an IFF_UP interface with a
229 * non-zero address, we'll return the last IFF_UP
232 * Since the order of the interfaces retrieved
233 * via SIOCGLIFCONF is not deterministic, this
234 * is largely silliness, but (a) "it's always
235 * been this way", and (b) no one consumes the
236 * interface name in the RARP case anyway.
240 (void) strncpy(interface
, ifr
->lifr_name
, LIFNAMSIZ
);
241 *dhcpflag
= (flifr
.lifr_flags
& IFF_DHCPRUNNING
) != 0;
242 sin
= (struct sockaddr_in
*)&ifr
->lifr_addr
;
243 if (isv4
&& (sin
->sin_addr
.s_addr
== INADDR_ANY
)) {
244 /* keep looking for a non-zero address */
250 return (found_one
? interface
: NULL
);
255 main(int argc
, char *argv
[])
257 char *root
, *interface
, *strategy
, dummy
;
259 boolean_t dhcp_running
= B_FALSE
;
261 root
= interface
= strategy
= NULL
;
264 root
= get_root_fstype();
266 if (!open_sockets()) {
267 (void) fprintf(stderr
,
268 "%s: cannot get interface information\n", program
);
273 * If diskless, perhaps boot properties were used to configure
276 if ((strcmp(root
, "nfs") == 0) && boot_properties_present()) {
277 strategy
= "bootprops";
279 interface
= get_first_interface(&dhcp_running
);
280 if (interface
== NULL
) {
281 (void) fprintf(stderr
,
282 "%s: cannot identify root interface.\n", program
);
287 (void) printf("%s %s %s\n", root
, interface
, strategy
);
293 * Handle the simple case where diskless dhcp tells us everything
296 if ((len
= sysinfo(SI_DHCP_CACHE
, &dummy
, sizeof (dummy
))) > 1) {
297 /* interface is first thing in cache. */
299 interface
= alloca(len
);
300 (void) sysinfo(SI_DHCP_CACHE
, interface
, len
);
301 (void) printf("%s %s %s\n", root
, interface
, strategy
);
307 * We're not "nfs dhcp", "nfs none" is impossible, and we don't handle
308 * "ufs rarp" (consumers are coded to deal with this reality), so
309 * there are three possible situations:
311 * 1. We're either "ufs dhcp" or "zfs dhcp" if there are any
312 * interfaces which have obtained their addresses through DHCP.
313 * That is, if there are any IFF_UP and non-IFF_VIRTUAL
314 * interfaces also have IFF_DHCPRUNNING set.
316 * 2. We're either "ufs none" or "zfs none" if our filesystem
317 * is local and there are no interfaces which have obtained
318 * their addresses through DHCP.
320 * 3. We're "nfs rarp" if our filesystem is remote and there's
321 * at least IFF_UP non-IFF_VIRTUAL interface (which there
322 * *must* be, since we're running over NFS somehow), then
323 * it must be RARP since SI_DHCP_CACHE call above failed.
324 * It's too bad there isn't an IFF_RARPRUNNING flag.
327 interface
= get_first_interface(&dhcp_running
);
332 if (strcmp(root
, "nfs") == 0) {
333 if (interface
== NULL
) {
334 (void) fprintf(stderr
,
335 "%s: cannot identify root interface.\n", program
);
339 if (strategy
== NULL
)
340 strategy
= "rarp"; /* must be rarp/bootparams */
342 if (interface
== NULL
|| strategy
== NULL
)
343 interface
= strategy
= "none";
346 (void) printf("%s %s %s\n", root
, interface
, strategy
);