xref: /titanic_41/usr/src/cmd/rcm_daemon/common/ip_rcm.c (revision 7a286c471efbab8562f7655a82931904703fffe0)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * This RCM module adds support to the RCM framework for IP managed
28  * interfaces.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <assert.h>
35 #include <string.h>
36 #include <synch.h>
37 #include <libintl.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <sys/types.h>
41 #include <sys/wait.h>
42 #include <sys/stat.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <stropts.h>
49 #include <strings.h>
50 #include <sys/sysmacros.h>
51 #include <inet/ip.h>
52 #include <libinetutil.h>
53 #include <libdllink.h>
54 #include <libgen.h>
55 #include <ipmp_admin.h>
56 
57 #include "rcm_module.h"
58 
59 /*
60  * Definitions
61  */
62 #ifndef lint
63 #define	_(x)	gettext(x)
64 #else
65 #define	_(x)	x
66 #endif
67 
68 /* Some generic well-knowns and defaults used in this module */
69 #define	ARP_MOD_NAME		"arp"		/* arp module */
70 #define	IP_MAX_MODS		9		/* max modules pushed on intr */
71 #define	MAX_RECONFIG_SIZE	1024		/* Max. reconfig string size */
72 
73 #define	RCM_LINK_PREFIX		"SUNW_datalink"	/* RCM datalink name prefix */
74 #define	RCM_LINK_RESOURCE_MAX	(13 + LINKID_STR_WIDTH)
75 
76 #define	RCM_STR_SUNW_IP		"SUNW_ip/"	/* IP address export prefix */
77 
78 #define	SBIN_IFCONFIG		"/sbin/ifconfig" /* ifconfig command */
79 #define	SBIN_IFPARSE		"/sbin/ifparse"	/* ifparse command */
80 #define	DHCPFILE_FMT		"/etc/dhcp.%s"	/* DHCP config file */
81 #define	CFGFILE_FMT_IPV4	"/etc/hostname.%s"  /* IPV4 config file */
82 #define	CFGFILE_FMT_IPV6	"/etc/hostname6.%s" /* IPV6 config file */
83 #define	CFG_CMDS_STD	" netmask + broadcast + up" /* Normal config string */
84 #define	CFG_DHCP_CMD		"dhcp wait 0"	/* command to start DHCP */
85 
86 /* Some useful macros */
87 #define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
88 #define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
89 #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
90 
91 /* Interface Cache state flags */
92 #define	CACHE_IF_STALE		0x1		/* stale cached data */
93 #define	CACHE_IF_NEW		0x2		/* new cached interface */
94 #define	CACHE_IF_OFFLINED	0x4		/* interface offlined */
95 #define	CACHE_IF_IGNORE		0x8		/* state held elsewhere */
96 
97 /* Network Cache lookup options */
98 #define	CACHE_NO_REFRESH	0x1		/* cache refresh not needed */
99 #define	CACHE_REFRESH		0x2		/* refresh cache */
100 
101 /* RCM IPMP Module specific property definitions */
102 #define	RCM_IPMP_MIN_REDUNDANCY	1		/* default min. redundancy */
103 
104 /* Stream module operations */
105 #define	MOD_INSERT		0	/* Insert a mid-stream module */
106 #define	MOD_REMOVE		1	/* Remove a mid-stream module */
107 #define	MOD_CHECK		2	/* Check mid-stream module safety */
108 
109 /*
110  * IP module data types
111  */
112 
113 /* Physical interface representation */
114 typedef struct ip_pif {
115 	char		pi_ifname[LIFNAMSIZ];	/* interface name */
116 	char		pi_grname[LIFGRNAMSIZ]; /* IPMP group name */
117 	struct ip_lif	*pi_lifs;		/* ptr to logical interfaces */
118 } ip_pif_t;
119 
120 /* Logical interface representation */
121 typedef struct ip_lif
122 {
123 	struct ip_lif		*li_next;	/* ptr to next lif */
124 	struct ip_lif		*li_prev;  	/* previous next ptr */
125 	ip_pif_t		*li_pif;	/* back ptr to phy int */
126 	ushort_t		li_ifnum;	/* interface number */
127 	union {
128 		sa_family_t		family;
129 		struct sockaddr_storage storage;
130 		struct sockaddr_in	ip4;    /* IPv4 */
131 		struct sockaddr_in6	ip6;    /* IPv6 */
132 	} li_addr;
133 	uint64_t		li_ifflags;	/* current IFF_* flags */
134 	int			li_modcnt;	/* # of modules */
135 	char	*li_modules[IP_MAX_MODS];	/* module list pushed */
136 	char	*li_reconfig;			/* Reconfiguration string */
137 	int32_t			li_cachestate;	/* cache state flags */
138 } ip_lif_t;
139 
140 /* Cache element */
141 typedef struct ip_cache
142 {
143 	struct ip_cache		*ip_next;	/* next cached resource */
144 	struct ip_cache		*ip_prev;	/* prev cached resource */
145 	char			*ip_resource;	/* resource name */
146 	ip_pif_t		*ip_pif;	/* ptr to phy int */
147 	int32_t			ip_ifred;	/* min. redundancy */
148 	int			ip_cachestate;	/* cache state flags */
149 } ip_cache_t;
150 
151 /*
152  * Global cache for network interfaces
153  */
154 static ip_cache_t	cache_head;
155 static ip_cache_t	cache_tail;
156 static mutex_t		cache_lock;
157 static int		events_registered = 0;
158 
159 static dladm_handle_t	dld_handle = NULL;
160 
161 /*
162  * RCM module interface prototypes
163  */
164 static int ip_register(rcm_handle_t *);
165 static int ip_unregister(rcm_handle_t *);
166 static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t,
167 			char **, char **, nvlist_t *, rcm_info_t **);
168 static int ip_suspend(rcm_handle_t *, char *, id_t,
169 			timespec_t *, uint_t, char **, rcm_info_t **);
170 static int ip_resume(rcm_handle_t *, char *, id_t, uint_t,
171 			char **, rcm_info_t **);
172 static int ip_offline(rcm_handle_t *, char *, id_t, uint_t,
173 			char **, rcm_info_t **);
174 static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
175 			char **, rcm_info_t **);
176 static int ip_remove(rcm_handle_t *, char *, id_t, uint_t,
177 			char **, rcm_info_t **);
178 static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t,
179 			char **, nvlist_t *, rcm_info_t **);
180 
181 /* Module private routines */
182 static void 	free_cache();
183 static int 	update_cache(rcm_handle_t *);
184 static void 	cache_remove(ip_cache_t *);
185 static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char);
186 static void 	free_node(ip_cache_t *);
187 static void 	cache_insert(ip_cache_t *);
188 static char 	*ip_usage(ip_cache_t *);
189 static int 	update_pif(rcm_handle_t *, int, int, struct lifreq *);
190 static int 	ip_ipmp_offline(ip_cache_t *);
191 static int	ip_ipmp_undo_offline(ip_cache_t *);
192 static int	if_cfginfo(ip_cache_t *, uint_t);
193 static int	if_unplumb(ip_cache_t *);
194 static int	if_replumb(ip_cache_t *);
195 static void 	ip_log_err(ip_cache_t *, char **, char *);
196 static char	*get_link_resource(const char *);
197 static void	clr_cfg_state(ip_pif_t *);
198 static int	modop(char *, char *, int, char);
199 static int	get_modlist(char *, ip_lif_t *);
200 static int	ip_domux2fd(int *, int *, int *, struct lifreq *);
201 static int	ip_plink(int, int, int, struct lifreq *);
202 static int	ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
203 			rcm_info_t **);
204 static int	ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
205 			rcm_info_t **);
206 static char 	**ip_get_addrlist(ip_cache_t *);
207 static void	ip_free_addrlist(char **);
208 static void	ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **,
209 			uint_t, rcm_info_t **);
210 static boolean_t ip_addrstr(ip_lif_t *, char *, size_t);
211 
212 static int if_configure(datalink_id_t);
213 static boolean_t isgrouped(const char *);
214 static int if_config_inst(const char *, FILE *, int, boolean_t);
215 static uint_t ntok(const char *cp);
216 static boolean_t ifconfig(const char *, const char *, const char *, boolean_t);
217 
218 /* Module-Private data */
219 static struct rcm_mod_ops ip_ops =
220 {
221 	RCM_MOD_OPS_VERSION,
222 	ip_register,
223 	ip_unregister,
224 	ip_get_info,
225 	ip_suspend,
226 	ip_resume,
227 	ip_offline,
228 	ip_undo_offline,
229 	ip_remove,
230 	NULL,
231 	NULL,
232 	ip_notify_event
233 };
234 
235 /*
236  * rcm_mod_init() - Update registrations, and return the ops structure.
237  */
238 struct rcm_mod_ops *
239 rcm_mod_init(void)
240 {
241 	char errmsg[DLADM_STRSIZE];
242 	dladm_status_t status;
243 
244 	rcm_log_message(RCM_TRACE1, "IP: mod_init\n");
245 
246 	cache_head.ip_next = &cache_tail;
247 	cache_head.ip_prev = NULL;
248 	cache_tail.ip_prev = &cache_head;
249 	cache_tail.ip_next = NULL;
250 	(void) mutex_init(&cache_lock, NULL, NULL);
251 
252 	if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
253 		rcm_log_message(RCM_WARNING,
254 		    "IP: mod_init failed: cannot get datalink handle: %s\n",
255 		    dladm_status2str(status, errmsg));
256 		return (NULL);
257 	}
258 
259 	/* Return the ops vectors */
260 	return (&ip_ops);
261 }
262 
263 /*
264  * rcm_mod_info() - Return a string describing this module.
265  */
266 const char *
267 rcm_mod_info(void)
268 {
269 	rcm_log_message(RCM_TRACE1, "IP: mod_info\n");
270 
271 	return ("IP Multipathing module version 1.23");
272 }
273 
274 /*
275  * rcm_mod_fini() - Destroy the network interfaces cache.
276  */
277 int
278 rcm_mod_fini(void)
279 {
280 	rcm_log_message(RCM_TRACE1, "IP: mod_fini\n");
281 
282 	free_cache();
283 	(void) mutex_destroy(&cache_lock);
284 
285 	dladm_close(dld_handle);
286 	return (RCM_SUCCESS);
287 }
288 
289 /*
290  * ip_register() - Make sure the cache is properly sync'ed, and its
291  *		 registrations are in order.
292  */
293 static int
294 ip_register(rcm_handle_t *hd)
295 {
296 	rcm_log_message(RCM_TRACE1, "IP: register\n");
297 
298 	/* Guard against bad arguments */
299 	assert(hd != NULL);
300 
301 	if (update_cache(hd) < 0)
302 		return (RCM_FAILURE);
303 
304 	/*
305 	 * Need to register interest in all new resources
306 	 * getting attached, so we get attach event notifications
307 	 */
308 	if (!events_registered) {
309 		if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
310 		    != RCM_SUCCESS) {
311 			rcm_log_message(RCM_ERROR,
312 			    _("IP: failed to register %s\n"),
313 			    RCM_RESOURCE_LINK_NEW);
314 			return (RCM_FAILURE);
315 		} else {
316 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
317 			    RCM_RESOURCE_LINK_NEW);
318 			events_registered++;
319 		}
320 	}
321 
322 	return (RCM_SUCCESS);
323 }
324 
325 /*
326  * ip_unregister() - Walk the cache, unregistering all the networks.
327  */
328 static int
329 ip_unregister(rcm_handle_t *hd)
330 {
331 	ip_cache_t *probe;
332 
333 	rcm_log_message(RCM_TRACE1, "IP: unregister\n");
334 
335 	/* Guard against bad arguments */
336 	assert(hd != NULL);
337 
338 	/* Walk the cache, unregistering everything */
339 	(void) mutex_lock(&cache_lock);
340 	probe = cache_head.ip_next;
341 	while (probe != &cache_tail) {
342 		if (rcm_unregister_interest(hd, probe->ip_resource, 0)
343 		    != RCM_SUCCESS) {
344 			/* unregister failed for whatever reason */
345 			(void) mutex_unlock(&cache_lock);
346 			return (RCM_FAILURE);
347 		}
348 		cache_remove(probe);
349 		free_node(probe);
350 		probe = cache_head.ip_next;
351 	}
352 	(void) mutex_unlock(&cache_lock);
353 
354 	/*
355 	 * Need to unregister interest in all new resources
356 	 */
357 	if (events_registered) {
358 		if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
359 		    != RCM_SUCCESS) {
360 			rcm_log_message(RCM_ERROR,
361 			    _("IP: failed to unregister %s\n"),
362 			    RCM_RESOURCE_LINK_NEW);
363 			return (RCM_FAILURE);
364 		} else {
365 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
366 			    RCM_RESOURCE_LINK_NEW);
367 			events_registered--;
368 		}
369 	}
370 
371 	return (RCM_SUCCESS);
372 }
373 
374 /*
375  * ip_offline() - Offline an interface.
376  */
377 static int
378 ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
379     char **errorp, rcm_info_t **depend_info)
380 {
381 	ip_cache_t *node;
382 	ip_pif_t *pif;
383 	boolean_t detachable = B_FALSE;
384 	boolean_t ipmp;
385 	int retval;
386 
387 	rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc);
388 
389 	/* Guard against bad arguments */
390 	assert(hd != NULL);
391 	assert(rsrc != NULL);
392 	assert(id == (id_t)0);
393 	assert(errorp != NULL);
394 	assert(depend_info != NULL);
395 
396 	/* Lock the cache and lookup the resource */
397 	(void) mutex_lock(&cache_lock);
398 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
399 	if (node == NULL) {
400 		ip_log_err(node, errorp, "Unrecognized resource");
401 		errno = ENOENT;
402 		(void) mutex_unlock(&cache_lock);
403 		return (RCM_SUCCESS);
404 	}
405 
406 	pif = node->ip_pif;
407 
408 	/* Establish default detachability criteria */
409 	if (flags & RCM_FORCE)
410 		detachable = B_TRUE;
411 
412 	/* Check if the interface is under IPMP */
413 	ipmp = (pif->pi_grname[0] != '\0');
414 
415 	/*
416 	 * Even if the interface is not under IPMP, it's possible that it's
417 	 * still okay to offline it as long as there are higher-level failover
418 	 * mechanisms for the addresses it owns (e.g., clustering).  In this
419 	 * case, ip_offlinelist() will return RCM_SUCCESS, and we charge on.
420 	 */
421 	if (!ipmp && !detachable) {
422 		/* Inform consumers of IP addresses being offlined */
423 		if (ip_offlinelist(hd, node, errorp, flags, depend_info) ==
424 		    RCM_SUCCESS) {
425 			rcm_log_message(RCM_DEBUG,
426 			    "IP: consumers agree on detach");
427 		} else {
428 			ip_log_err(node, errorp,
429 			    "Device consumers prohibit offline");
430 			(void) mutex_unlock(&cache_lock);
431 			return (RCM_FAILURE);
432 		}
433 	}
434 
435 	/* Check if it's a query */
436 	if (flags & RCM_QUERY) {
437 		rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n",
438 		    rsrc);
439 		(void) mutex_unlock(&cache_lock);
440 		return (RCM_SUCCESS);
441 	}
442 
443 	/* Check detachability, save configuration if detachable */
444 	if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) {
445 		node->ip_cachestate |= CACHE_IF_IGNORE;
446 		rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc);
447 		(void) mutex_unlock(&cache_lock);
448 		return (RCM_SUCCESS);
449 	}
450 
451 	/* standalone detachable device */
452 	if (!ipmp) {
453 		if (if_unplumb(node) < 0) {
454 			ip_log_err(node, errorp,
455 			    "Failed to unplumb the device");
456 
457 			errno = EIO;
458 			(void) mutex_unlock(&cache_lock);
459 			return (RCM_FAILURE);
460 		}
461 
462 		node->ip_cachestate |= CACHE_IF_OFFLINED;
463 		rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc);
464 		(void) mutex_unlock(&cache_lock);
465 		return (RCM_SUCCESS);
466 	}
467 
468 	/*
469 	 * This is an IPMP interface that can be offlined.
470 	 * Request in.mpathd(1M) to offline the physical interface.
471 	 */
472 	if ((retval = ip_ipmp_offline(node)) != IPMP_SUCCESS)
473 		ip_log_err(node, errorp, "in.mpathd offline failed");
474 
475 	if (retval == IPMP_EMINRED && !detachable) {
476 		/*
477 		 * in.mpathd(1M) could not offline the device because it was
478 		 * the last interface in the group.  However, it's possible
479 		 * that it's still okay to offline it as long as there are
480 		 * higher-level failover mechanisms for the addresses it owns
481 		 * (e.g., clustering).  In this case, ip_offlinelist() will
482 		 * return RCM_SUCCESS, and we charge on.
483 		 */
484 		/* Inform consumers of IP addresses being offlined */
485 		if (ip_offlinelist(hd, node, errorp, flags,
486 		    depend_info) == RCM_SUCCESS) {
487 			rcm_log_message(RCM_DEBUG,
488 			    "IP: consumers agree on detach");
489 		} else {
490 			ip_log_err(node, errorp,
491 			    "Device consumers prohibit offline");
492 			(void) mutex_unlock(&cache_lock);
493 			errno = EBUSY;
494 			return (RCM_FAILURE);
495 		}
496 	}
497 
498 	if (if_unplumb(node) < 0) {
499 		rcm_log_message(RCM_ERROR,
500 		    _("IP: Unplumb failed (%s)\n"),
501 		    pif->pi_ifname);
502 
503 		/* Request in.mpathd to undo the offline */
504 		if (ip_ipmp_undo_offline(node) != IPMP_SUCCESS) {
505 			ip_log_err(node, errorp, "Undo offline failed");
506 			(void) mutex_unlock(&cache_lock);
507 			return (RCM_FAILURE);
508 		}
509 		(void) mutex_unlock(&cache_lock);
510 		return (RCM_FAILURE);
511 	}
512 
513 	node->ip_cachestate |= CACHE_IF_OFFLINED;
514 	rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc);
515 	(void) mutex_unlock(&cache_lock);
516 	return (RCM_SUCCESS);
517 }
518 
519 /*
520  * ip_undo_offline() - Undo offline of a previously offlined device.
521  */
522 /*ARGSUSED*/
523 static int
524 ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
525     char **errorp, rcm_info_t **depend_info)
526 {
527 	ip_cache_t *node;
528 
529 	rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc);
530 
531 	/* Guard against bad arguments */
532 	assert(hd != NULL);
533 	assert(rsrc != NULL);
534 	assert(id == (id_t)0);
535 	assert(errorp != NULL);
536 	assert(depend_info != NULL);
537 
538 	(void) mutex_lock(&cache_lock);
539 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
540 
541 	if (node == NULL) {
542 		ip_log_err(node, errorp, "No such device");
543 		(void) mutex_unlock(&cache_lock);
544 		errno = ENOENT;
545 		return (RCM_FAILURE);
546 	}
547 
548 	/* Check if no attempt should be made to online the device here */
549 	if (node->ip_cachestate & CACHE_IF_IGNORE) {
550 		node->ip_cachestate &= ~(CACHE_IF_IGNORE);
551 		(void) mutex_unlock(&cache_lock);
552 		return (RCM_SUCCESS);
553 	}
554 
555 	/* Check if the interface was previously offlined */
556 	if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) {
557 		ip_log_err(node, errorp, "Device not offlined");
558 		(void) mutex_unlock(&cache_lock);
559 		errno = ENOTSUP;
560 		return (RCM_FAILURE);
561 	}
562 
563 	if (if_replumb(node) == -1) {
564 		/* re-plumb failed */
565 		ip_log_err(node, errorp, "Replumb failed");
566 		(void) mutex_unlock(&cache_lock);
567 		errno = EIO;
568 		return (RCM_FAILURE);
569 
570 	}
571 
572 	/* Inform consumers about IP addresses being un-offlined */
573 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
574 
575 	node->ip_cachestate &= ~(CACHE_IF_OFFLINED);
576 	rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc);
577 	(void) mutex_unlock(&cache_lock);
578 	return (RCM_SUCCESS);
579 }
580 
581 /*
582  * ip_get_info() - Gather usage information for this resource.
583  */
584 /*ARGSUSED*/
585 int
586 ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
587     char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info)
588 {
589 	ip_cache_t *node;
590 	char *infostr;
591 
592 	/* Guard against bad arguments */
593 	assert(hd != NULL);
594 	assert(rsrc != NULL);
595 	assert(id == (id_t)0);
596 	assert(usagep != NULL);
597 	assert(errorp != NULL);
598 	assert(depend_info != NULL);
599 
600 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc);
601 
602 	(void) mutex_lock(&cache_lock);
603 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
604 	if (!node) {
605 		rcm_log_message(RCM_INFO,
606 		    _("IP: get_info(%s) unrecognized resource\n"), rsrc);
607 		(void) mutex_unlock(&cache_lock);
608 		errno = ENOENT;
609 		return (RCM_FAILURE);
610 	}
611 
612 	infostr = ip_usage(node);
613 
614 	if (infostr == NULL) {
615 		/* most likely malloc failure */
616 		rcm_log_message(RCM_ERROR,
617 		    _("IP: get_info(%s) malloc failure\n"), rsrc);
618 		(void) mutex_unlock(&cache_lock);
619 		errno = ENOMEM;
620 		*errorp = NULL;
621 		return (RCM_FAILURE);
622 	}
623 
624 	/* Set client/role properties */
625 	(void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP");
626 
627 	/* Set usage property, infostr will be freed by caller */
628 	*usagep = infostr;
629 
630 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n",
631 	    rsrc, infostr);
632 
633 	(void) mutex_unlock(&cache_lock);
634 	return (RCM_SUCCESS);
635 }
636 
637 /*
638  * ip_suspend() - Nothing to do, always okay
639  */
640 /*ARGSUSED*/
641 static int
642 ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
643 			uint_t flags, char **errorp, rcm_info_t **depend_info)
644 {
645 	/* Guard against bad arguments */
646 	assert(hd != NULL);
647 	assert(rsrc != NULL);
648 	assert(id == (id_t)0);
649 	assert(interval != NULL);
650 	assert(errorp != NULL);
651 	assert(depend_info != NULL);
652 
653 	rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc);
654 	return (RCM_SUCCESS);
655 }
656 
657 /*
658  * ip_resume() - Nothing to do, always okay
659  */
660 /*ARGSUSED*/
661 static int
662 ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
663 		char **errorp, rcm_info_t ** depend_info)
664 {
665 	/* Guard against bad arguments */
666 	assert(hd != NULL);
667 	assert(rsrc != NULL);
668 	assert(id == (id_t)0);
669 	assert(errorp != NULL);
670 	assert(depend_info != NULL);
671 
672 	rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc);
673 
674 	return (RCM_SUCCESS);
675 }
676 
677 /*
678  * ip_remove() - remove a resource from cache
679  */
680 /*ARGSUSED*/
681 static int
682 ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
683 		char **errorp, rcm_info_t **depend_info)
684 {
685 	ip_cache_t *node;
686 
687 	/* Guard against bad arguments */
688 	assert(hd != NULL);
689 	assert(rsrc != NULL);
690 	assert(id == (id_t)0);
691 	assert(errorp != NULL);
692 	assert(depend_info != NULL);
693 
694 	rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc);
695 
696 	(void) mutex_lock(&cache_lock);
697 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
698 	if (!node) {
699 		rcm_log_message(RCM_INFO,
700 		    _("IP: remove(%s) unrecognized resource\n"), rsrc);
701 		(void) mutex_unlock(&cache_lock);
702 		errno = ENOENT;
703 		return (RCM_FAILURE);
704 	}
705 
706 	/* remove the cached entry for the resource */
707 	cache_remove(node);
708 	free_node(node);
709 
710 	(void) mutex_unlock(&cache_lock);
711 	return (RCM_SUCCESS);
712 }
713 
714 /*
715  * ip_notify_event - Project private implementation to receive new resource
716  *		   events. It intercepts all new resource events. If the
717  *		   new resource is a network resource, pass up a notify
718  *		   for it too. The new resource need not be cached, since
719  *		   it is done at register again.
720  */
721 /*ARGSUSED*/
722 static int
723 ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
724 			char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
725 {
726 	datalink_id_t	linkid;
727 	nvpair_t *nvp = NULL;
728 	uint64_t id64;
729 
730 	assert(hd != NULL);
731 	assert(rsrc != NULL);
732 	assert(id == (id_t)0);
733 	assert(nvl != NULL);
734 
735 	rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc);
736 
737 	if (!STREQ(rsrc, RCM_RESOURCE_LINK_NEW)) {
738 		rcm_log_message(RCM_INFO,
739 		    _("IP: unrecognized event for %s\n"), rsrc);
740 		ip_log_err(NULL, errorp, "unrecognized event");
741 		errno = EINVAL;
742 		return (RCM_FAILURE);
743 	}
744 
745 	/* Update cache to reflect latest interfaces */
746 	if (update_cache(hd) < 0) {
747 		rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n"));
748 		ip_log_err(NULL, errorp, "Private Cache update failed");
749 		return (RCM_FAILURE);
750 	}
751 
752 	rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n");
753 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
754 		if (STREQ(nvpair_name(nvp), RCM_NV_LINKID)) {
755 			if (nvpair_value_uint64(nvp, &id64) != 0) {
756 				rcm_log_message(RCM_WARNING,
757 				    _("IP: cannot get linkid\n"));
758 				return (RCM_FAILURE);
759 			}
760 			linkid = (datalink_id_t)id64;
761 			if (if_configure(linkid) != 0) {
762 				rcm_log_message(RCM_ERROR,
763 				    _("IP: Configuration failed (%u)\n"),
764 				    linkid);
765 				ip_log_err(NULL, errorp,
766 				    "Failed configuring one or more IP "
767 				    "addresses");
768 			}
769 
770 			/* Notify all IP address consumers */
771 			ip_consumer_notify(hd, linkid, errorp, flags,
772 			    depend_info);
773 		}
774 	}
775 
776 	rcm_log_message(RCM_TRACE1,
777 	    "IP: notify_event: device configuration complete\n");
778 
779 	return (RCM_SUCCESS);
780 }
781 
782 /*
783  * ip_usage - Determine the usage of a device.  Call with cache_lock held.
784  *	    The returned buffer is owned by caller, and the caller
785  *	    must free it up when done.
786  */
787 static char *
788 ip_usage(ip_cache_t *node)
789 {
790 	ip_lif_t *lif;
791 	uint_t numup;
792 	char *sep, *buf, *linkidstr;
793 	datalink_id_t linkid;
794 	const char *msg;
795 	char link[MAXLINKNAMELEN];
796 	char addrstr[INET6_ADDRSTRLEN];
797 	char errmsg[DLADM_STRSIZE];
798 	dladm_status_t status;
799 	boolean_t offline, ipmp;
800 	size_t bufsz = 0;
801 
802 	rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource);
803 
804 	/*
805 	 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid>
806 	 */
807 	linkidstr = strchr(node->ip_resource, '/');
808 	assert(linkidstr != NULL);
809 	linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource;
810 
811 	errno = 0;
812 	linkid = strtol(linkidstr, &buf, 10);
813 	if (errno != 0 || *buf != '\0') {
814 		rcm_log_message(RCM_ERROR,
815 		    _("IP: usage(%s) parse linkid failure (%s)\n"),
816 		    node->ip_resource, strerror(errno));
817 		return (NULL);
818 	}
819 
820 	if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL, NULL,
821 	    NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
822 		rcm_log_message(RCM_ERROR,
823 		    _("IP: usage(%s) get link name failure(%s)\n"),
824 		    node->ip_resource, dladm_status2str(status, errmsg));
825 		return (NULL);
826 	}
827 
828 	/* TRANSLATION_NOTE: separator used between IP addresses */
829 	sep = _(", ");
830 
831 	numup = 0;
832 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next)
833 		if (lif->li_ifflags & IFF_UP)
834 			numup++;
835 
836 	ipmp = (node->ip_pif->pi_grname[0] != '\0');
837 	offline = ((node->ip_cachestate & CACHE_IF_OFFLINED) != 0);
838 
839 	if (offline) {
840 		msg = _("offlined");
841 	} else if (numup == 0) {
842 		msg = _("plumbed but down");
843 	} else {
844 		if (ipmp) {
845 			msg = _("providing connectivity for IPMP group ");
846 			bufsz += LIFGRNAMSIZ;
847 		} else {
848 			msg = _("hosts IP addresses: ");
849 			bufsz += (numup * (INET6_ADDRSTRLEN + strlen(sep)));
850 		}
851 	}
852 
853 	bufsz += strlen(link) + strlen(msg) + 1;
854 	if ((buf = malloc(bufsz)) == NULL) {
855 		rcm_log_message(RCM_ERROR,
856 		    _("IP: usage(%s) malloc failure(%s)\n"),
857 		    node->ip_resource, strerror(errno));
858 		return (NULL);
859 	}
860 	(void) snprintf(buf, bufsz, "%s: %s", link, msg);
861 
862 	if (!offline && numup > 0) {
863 		if (ipmp) {
864 			(void) strlcat(buf, node->ip_pif->pi_grname, bufsz);
865 		} else {
866 			lif = node->ip_pif->pi_lifs;
867 			for (; lif != NULL; lif = lif->li_next) {
868 				if (!(lif->li_ifflags & IFF_UP))
869 					continue;
870 
871 				if (!ip_addrstr(lif, addrstr, sizeof (addrstr)))
872 					continue;
873 
874 				(void) strlcat(buf, addrstr, bufsz);
875 				if (--numup > 0)
876 					(void) strlcat(buf, sep, bufsz);
877 			}
878 		}
879 	}
880 
881 	rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
882 	    node->ip_resource, buf);
883 
884 	return (buf);
885 }
886 
887 static boolean_t
888 ip_addrstr(ip_lif_t *lif, char *addrstr, size_t addrsize)
889 {
890 	int af = lif->li_addr.family;
891 	void *addr;
892 
893 	if (af == AF_INET6) {
894 		addr = &lif->li_addr.ip6.sin6_addr;
895 	} else if (af == AF_INET) {
896 		addr = &lif->li_addr.ip4.sin_addr;
897 	} else {
898 		rcm_log_message(RCM_DEBUG,
899 		    "IP: unknown addr family %d, assuming AF_INET\n", af);
900 		af = AF_INET;
901 		addr = &lif->li_addr.ip4.sin_addr;
902 	}
903 	if (inet_ntop(af, addr, addrstr, addrsize) == NULL) {
904 		rcm_log_message(RCM_ERROR,
905 		    _("IP: inet_ntop: %s\n"), strerror(errno));
906 		return (B_FALSE);
907 	}
908 
909 	rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr);
910 	return (B_TRUE);
911 }
912 
913 /*
914  * Cache management routines, all cache management functions should be
915  * be called with cache_lock held.
916  */
917 
918 /*
919  * cache_lookup() - Get a cache node for a resource.
920  *		  Call with cache lock held.
921  *
922  * This ensures that the cache is consistent with the system state and
923  * returns a pointer to the cache element corresponding to the resource.
924  */
925 static ip_cache_t *
926 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
927 {
928 	ip_cache_t *probe;
929 
930 	rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc);
931 
932 	if ((options & CACHE_REFRESH) && (hd != NULL)) {
933 		/* drop lock since update locks cache again */
934 		(void) mutex_unlock(&cache_lock);
935 		(void) update_cache(hd);
936 		(void) mutex_lock(&cache_lock);
937 	}
938 
939 	probe = cache_head.ip_next;
940 	while (probe != &cache_tail) {
941 		if (probe->ip_resource &&
942 		    STREQ(rsrc, probe->ip_resource)) {
943 			rcm_log_message(RCM_TRACE2,
944 			    "IP: cache lookup success(%s)\n", rsrc);
945 			return (probe);
946 		}
947 		probe = probe->ip_next;
948 	}
949 	return (NULL);
950 }
951 
952 /*
953  * free_node - Free a node from the cache
954  *	     Call with cache_lock held.
955  */
956 static void
957 free_node(ip_cache_t *node)
958 {
959 	ip_pif_t *pif;
960 	ip_lif_t *lif, *tmplif;
961 
962 	if (node) {
963 		if (node->ip_resource) {
964 			free(node->ip_resource);
965 		}
966 
967 		/* free the pif */
968 		pif = node->ip_pif;
969 		if (pif) {
970 			/* free logical interfaces */
971 			lif = pif->pi_lifs;
972 			while (lif) {
973 				tmplif = lif->li_next;
974 				free(lif);
975 				lif = tmplif;
976 			}
977 			free(pif);
978 		}
979 		free(node);
980 	}
981 }
982 
983 /*
984  * cache_insert - Insert a resource node in cache
985  *		Call with the cache_lock held.
986  */
987 static void
988 cache_insert(ip_cache_t *node)
989 {
990 	rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n",
991 	    node->ip_resource);
992 
993 	/* insert at the head for best performance */
994 	node->ip_next = cache_head.ip_next;
995 	node->ip_prev = &cache_head;
996 
997 	node->ip_next->ip_prev = node;
998 	node->ip_prev->ip_next = node;
999 }
1000 
1001 /*
1002  * cache_remove() - Remove a resource node from cache.
1003  *		  Call with the cache_lock held.
1004  */
1005 static void
1006 cache_remove(ip_cache_t *node)
1007 {
1008 	rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n",
1009 	    node->ip_resource);
1010 
1011 	node->ip_next->ip_prev = node->ip_prev;
1012 	node->ip_prev->ip_next = node->ip_next;
1013 	node->ip_next = NULL;
1014 	node->ip_prev = NULL;
1015 }
1016 
1017 /*
1018  * update_pif() - Update physical interface properties
1019  *		Call with cache_lock held
1020  */
1021 /*ARGSUSED*/
1022 static int
1023 update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
1024 {
1025 	char *rsrc;
1026 	ifspec_t ifspec;
1027 	ushort_t ifnumber = 0;
1028 	ip_cache_t *probe;
1029 	ip_pif_t pif;
1030 	ip_pif_t *probepif;
1031 	ip_lif_t *probelif;
1032 	struct lifreq lifreq;
1033 	struct sockaddr_storage ifaddr;
1034 	uint64_t ifflags;
1035 	int lif_listed = 0;
1036 
1037 	rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", lifr->lifr_name);
1038 
1039 	if (!ifparse_ifspec(lifr->lifr_name, &ifspec)) {
1040 		rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"),
1041 		    lifr->lifr_name);
1042 		return (-1);
1043 	}
1044 
1045 	(void) snprintf(pif.pi_ifname, sizeof (pif.pi_ifname), "%s%d",
1046 	    ifspec.ifsp_devnm, ifspec.ifsp_ppa);
1047 	if (ifspec.ifsp_lunvalid)
1048 		ifnumber = ifspec.ifsp_lun;
1049 
1050 	/* Get the interface flags */
1051 	(void) strlcpy(lifreq.lifr_name, lifr->lifr_name, LIFNAMSIZ);
1052 	if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
1053 		if (errno != ENXIO) {
1054 			rcm_log_message(RCM_ERROR,
1055 			    _("IP: SIOCGLIFFLAGS(%s): %s\n"),
1056 			    lifreq.lifr_name, strerror(errno));
1057 		}
1058 		return (-1);
1059 	}
1060 	(void) memcpy(&ifflags, &lifreq.lifr_flags, sizeof (ifflags));
1061 
1062 	/*
1063 	 * Ignore interfaces that are always incapable of DR:
1064 	 *   - IFF_VIRTUAL:	e.g., loopback and vni
1065 	 *   - IFF_POINTOPOINT:	e.g., sppp and ip.tun
1066 	 *   - !IFF_MULTICAST:	e.g., ip.6to4tun
1067 	 *   - IFF_IPMP:	IPMP meta-interfaces
1068 	 *
1069 	 * Note: The !IFF_MULTICAST check can be removed once iptun is
1070 	 * implemented as a datalink.
1071 	 */
1072 	if (!(ifflags & IFF_MULTICAST) ||
1073 	    (ifflags & (IFF_POINTOPOINT | IFF_VIRTUAL | IFF_IPMP))) {
1074 		rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n",
1075 		    pif.pi_ifname);
1076 		return (0);
1077 	}
1078 
1079 	/* Get the interface group name for this interface */
1080 	if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) {
1081 		if (errno != ENXIO) {
1082 			rcm_log_message(RCM_ERROR,
1083 			    _("IP: SIOCGLIFGROUPNAME(%s): %s\n"),
1084 			    lifreq.lifr_name, strerror(errno));
1085 		}
1086 		return (-1);
1087 	}
1088 
1089 	/* copy the group name */
1090 	(void) strlcpy(pif.pi_grname, lifreq.lifr_groupname,
1091 	    sizeof (pif.pi_grname));
1092 
1093 	/* Get the interface address for this interface */
1094 	if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) {
1095 		if (errno != ENXIO) {
1096 			rcm_log_message(RCM_ERROR,
1097 			    _("IP: SIOCGLIFADDR(%s): %s\n"),
1098 			    lifreq.lifr_name, strerror(errno));
1099 			return (-1);
1100 		}
1101 	}
1102 	(void) memcpy(&ifaddr, &lifreq.lifr_addr, sizeof (ifaddr));
1103 
1104 	rsrc = get_link_resource(pif.pi_ifname);
1105 	if (rsrc == NULL) {
1106 		rcm_log_message(RCM_ERROR,
1107 		    _("IP: get_link_resource(%s) failed\n"),
1108 		    lifreq.lifr_name);
1109 		return (-1);
1110 	}
1111 
1112 	probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
1113 	if (probe != NULL) {
1114 		free(rsrc);
1115 		probe->ip_cachestate &= ~(CACHE_IF_STALE);
1116 	} else {
1117 		if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) {
1118 			/* malloc errors are bad */
1119 			free(rsrc);
1120 			rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1121 			    strerror(errno));
1122 			return (-1);
1123 		}
1124 
1125 		probe->ip_resource = rsrc;
1126 		probe->ip_pif = NULL;
1127 		probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY;
1128 		probe->ip_cachestate |= CACHE_IF_NEW;
1129 
1130 		cache_insert(probe);
1131 	}
1132 
1133 	probepif = probe->ip_pif;
1134 	if (probepif != NULL) {
1135 		/* Check if lifs need to be updated */
1136 		probelif = probepif->pi_lifs;
1137 		while (probelif != NULL) {
1138 			if ((probelif->li_ifnum == ifnumber) &&
1139 			    (probelif->li_addr.family == ifaddr.ss_family)) {
1140 
1141 				rcm_log_message(RCM_TRACE2,
1142 				    "IP: refreshing lifs for %s, ifnum=%d\n",
1143 				    pif.pi_ifname, probelif->li_ifnum);
1144 
1145 				/* refresh lif properties */
1146 				(void) memcpy(&probelif->li_addr, &ifaddr,
1147 				    sizeof (probelif->li_addr));
1148 
1149 				probelif->li_ifflags = ifflags;
1150 
1151 				lif_listed++;
1152 				probelif->li_cachestate &= ~(CACHE_IF_STALE);
1153 				break;
1154 			}
1155 			probelif = probelif->li_next;
1156 		}
1157 	}
1158 
1159 	if (probepif == NULL) {
1160 		if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) {
1161 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1162 			    strerror(errno));
1163 			if (probe->ip_pif == NULL) {
1164 				/* we created it, so clean it up */
1165 				free(probe);
1166 			}
1167 			return (-1);
1168 		}
1169 
1170 		probe->ip_pif = probepif;
1171 
1172 		/* Save interface name */
1173 		(void) memcpy(&probepif->pi_ifname, &pif.pi_ifname,
1174 		    sizeof (pif.pi_ifname));
1175 	}
1176 
1177 	/* save the group name */
1178 	(void) strlcpy(probepif->pi_grname, pif.pi_grname,
1179 	    sizeof (pif.pi_grname));
1180 
1181 	/* add lif, if this is a lif and it is not in cache */
1182 	if (!lif_listed) {
1183 		rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n",
1184 		    pif.pi_ifname);
1185 
1186 		if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) {
1187 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1188 			    strerror(errno));
1189 			return (-1);
1190 		}
1191 
1192 		/* save lif properties */
1193 		(void) memcpy(&probelif->li_addr, &ifaddr,
1194 		    sizeof (probelif->li_addr));
1195 
1196 		probelif->li_ifnum = ifnumber;
1197 		probelif->li_ifflags = ifflags;
1198 
1199 		/* insert us at the head of the lif list */
1200 		probelif->li_next = probepif->pi_lifs;
1201 		if (probelif->li_next != NULL) {
1202 			probelif->li_next->li_prev = probelif;
1203 		}
1204 		probelif->li_prev = NULL;
1205 		probelif->li_pif = probepif;
1206 
1207 		probepif->pi_lifs = probelif;
1208 	}
1209 
1210 	rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n",
1211 	    probe->ip_resource);
1212 
1213 	return (0);
1214 }
1215 
1216 /*
1217  * update_ipifs() - Determine all network interfaces in the system
1218  *		  Call with cache_lock held
1219  */
1220 static int
1221 update_ipifs(rcm_handle_t *hd, int af)
1222 {
1223 	int sock;
1224 	char *buf;
1225 	struct lifnum lifn;
1226 	struct lifconf lifc;
1227 	struct lifreq *lifrp;
1228 	int i;
1229 
1230 	rcm_log_message(RCM_TRACE2, "IP: update_ipifs\n");
1231 
1232 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
1233 		rcm_log_message(RCM_ERROR,
1234 		    _("IP: failure opening %s socket: %s\n"),
1235 		    af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
1236 		return (-1);
1237 	}
1238 
1239 	lifn.lifn_family = af;
1240 	lifn.lifn_flags = LIFC_UNDER_IPMP;
1241 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
1242 		rcm_log_message(RCM_ERROR,
1243 		    _("IP: SIOCLGIFNUM failed: %s\n"),
1244 		    strerror(errno));
1245 		(void) close(sock);
1246 		return (-1);
1247 	}
1248 
1249 	if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) {
1250 		rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1251 		    strerror(errno));
1252 		(void) close(sock);
1253 		return (-1);
1254 	}
1255 
1256 	lifc.lifc_family = af;
1257 	lifc.lifc_flags = LIFC_UNDER_IPMP;
1258 	lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count;
1259 	lifc.lifc_buf = buf;
1260 
1261 	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
1262 		rcm_log_message(RCM_ERROR,
1263 		    _("IP: SIOCGLIFCONF failed: %s\n"),
1264 		    strerror(errno));
1265 		free(buf);
1266 		(void) close(sock);
1267 		return (-1);
1268 	}
1269 
1270 	/* now we need to search for active interfaces */
1271 	lifrp = lifc.lifc_req;
1272 	for (i = 0; i < lifn.lifn_count; i++) {
1273 		(void) update_pif(hd, af, sock, lifrp);
1274 		lifrp++;
1275 	}
1276 
1277 	free(buf);
1278 	(void) close(sock);
1279 	return (0);
1280 }
1281 
1282 /*
1283  * update_cache() - Update cache with latest interface info
1284  */
1285 static int
1286 update_cache(rcm_handle_t *hd)
1287 {
1288 	ip_cache_t *probe;
1289 	struct ip_lif *lif;
1290 	struct ip_lif *nextlif;
1291 	int rv;
1292 	int i;
1293 
1294 	rcm_log_message(RCM_TRACE2, "IP: update_cache\n");
1295 
1296 	(void) mutex_lock(&cache_lock);
1297 
1298 	/* first we walk the entire cache, marking each entry stale */
1299 	probe = cache_head.ip_next;
1300 	while (probe != &cache_tail) {
1301 		probe->ip_cachestate |= CACHE_IF_STALE;
1302 		if ((probe->ip_pif != NULL) &&
1303 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1304 			while (lif != NULL) {
1305 				lif->li_cachestate |= CACHE_IF_STALE;
1306 				lif = lif->li_next;
1307 			}
1308 		}
1309 		probe = probe->ip_next;
1310 	}
1311 
1312 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n");
1313 	if (update_ipifs(hd, AF_INET) < 0) {
1314 		(void) mutex_unlock(&cache_lock);
1315 		return (-1);
1316 	}
1317 
1318 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n");
1319 	if (update_ipifs(hd, AF_INET6) < 0) {
1320 		(void) mutex_unlock(&cache_lock);
1321 		return (-1);
1322 	}
1323 
1324 	probe = cache_head.ip_next;
1325 	/* unregister devices that are not offlined and still in cache */
1326 	while (probe != &cache_tail) {
1327 		ip_cache_t *freeit;
1328 		if ((probe->ip_pif != NULL) &&
1329 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1330 			/* clear stale lifs */
1331 			while (lif != NULL) {
1332 				if (lif->li_cachestate & CACHE_IF_STALE) {
1333 					nextlif = lif->li_next;
1334 					if (lif->li_prev != NULL)
1335 						lif->li_prev->li_next = nextlif;
1336 					if (nextlif != NULL)
1337 						nextlif->li_prev = lif->li_prev;
1338 					if (probe->ip_pif->pi_lifs == lif)
1339 						probe->ip_pif->pi_lifs =
1340 						    nextlif;
1341 					for (i = 0; i < IP_MAX_MODS; i++) {
1342 						free(lif->li_modules[i]);
1343 					}
1344 					free(lif->li_reconfig);
1345 					free(lif);
1346 					lif = nextlif;
1347 				} else {
1348 					lif = lif->li_next;
1349 				}
1350 			}
1351 		}
1352 		if ((probe->ip_cachestate & CACHE_IF_STALE) &&
1353 		    !(probe->ip_cachestate & CACHE_IF_OFFLINED)) {
1354 			(void) rcm_unregister_interest(hd, probe->ip_resource,
1355 			    0);
1356 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
1357 			    probe->ip_resource);
1358 			freeit = probe;
1359 			probe = probe->ip_next;
1360 			cache_remove(freeit);
1361 			free_node(freeit);
1362 			continue;
1363 		}
1364 
1365 		if (!(probe->ip_cachestate & CACHE_IF_NEW)) {
1366 			probe = probe->ip_next;
1367 			continue;
1368 		}
1369 
1370 		rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL);
1371 		if (rv != RCM_SUCCESS) {
1372 			rcm_log_message(RCM_ERROR,
1373 			    _("IP: failed to register %s\n"),
1374 			    probe->ip_resource);
1375 			(void) mutex_unlock(&cache_lock);
1376 			return (-1);
1377 		} else {
1378 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
1379 			    probe->ip_resource);
1380 			probe->ip_cachestate &= ~(CACHE_IF_NEW);
1381 		}
1382 		probe = probe->ip_next;
1383 	}
1384 
1385 	(void) mutex_unlock(&cache_lock);
1386 	return (0);
1387 }
1388 
1389 /*
1390  * free_cache() - Empty the cache
1391  */
1392 static void
1393 free_cache()
1394 {
1395 	ip_cache_t *probe;
1396 
1397 	rcm_log_message(RCM_TRACE2, "IP: free_cache\n");
1398 
1399 	(void) mutex_lock(&cache_lock);
1400 	probe = cache_head.ip_next;
1401 	while (probe != &cache_tail) {
1402 		cache_remove(probe);
1403 		free_node(probe);
1404 		probe = cache_head.ip_next;
1405 	}
1406 	(void) mutex_unlock(&cache_lock);
1407 }
1408 
1409 /*
1410  * ip_log_err() - RCM error log wrapper
1411  */
1412 static void
1413 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
1414 {
1415 	char *ifname = NULL;
1416 	int size;
1417 	const char *errfmt;
1418 	char *error = NULL;
1419 
1420 	if ((node != NULL) && (node->ip_pif != NULL) &&
1421 	    (node->ip_pif->pi_ifname != NULL)) {
1422 		ifname = node->ip_pif->pi_ifname;
1423 	}
1424 
1425 	if (ifname == NULL) {
1426 		rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg);
1427 		errfmt = _("IP: %s");
1428 		size = strlen(errfmt) + strlen(errmsg) + 1;
1429 		if (errorp != NULL && (error = malloc(size)) != NULL)
1430 			(void) snprintf(error, size, errfmt, errmsg);
1431 	} else {
1432 		rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname);
1433 		errfmt = _("IP: %s(%s)");
1434 		size = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1;
1435 		if (errorp != NULL && (error = malloc(size)) != NULL)
1436 			(void) snprintf(error, size, errfmt, errmsg, ifname);
1437 	}
1438 
1439 	if (errorp != NULL)
1440 		*errorp = error;
1441 }
1442 
1443 /*
1444  * if_cfginfo() - Save off the config info for all interfaces
1445  */
1446 static int
1447 if_cfginfo(ip_cache_t *node, uint_t force)
1448 {
1449 	ip_lif_t *lif;
1450 	ip_pif_t *pif;
1451 	int i;
1452 	FILE *fp;
1453 	char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
1454 	char buf[MAX_RECONFIG_SIZE];
1455 
1456 	rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource);
1457 
1458 	pif = node->ip_pif;
1459 	lif = pif->pi_lifs;
1460 
1461 	while (lif != NULL) {
1462 		/* Make a list of modules pushed and save */
1463 		if (lif->li_ifnum == 0) {	/* physical instance */
1464 			if (get_modlist(pif->pi_ifname, lif) == -1) {
1465 				rcm_log_message(RCM_ERROR,
1466 				    _("IP: get modlist error (%s) %s\n"),
1467 				    pif->pi_ifname, strerror(errno));
1468 				clr_cfg_state(pif);
1469 				return (-1);
1470 			}
1471 
1472 			if (!force) {
1473 				/* Look if unknown modules have been inserted */
1474 				for (i = (lif->li_modcnt - 2); i > 0; i--) {
1475 					if (modop(pif->pi_ifname,
1476 					    lif->li_modules[i],
1477 					    i, MOD_CHECK) == -1) {
1478 						rcm_log_message(RCM_ERROR,
1479 						    _("IP: module %s@%d\n"),
1480 						    lif->li_modules[i], i);
1481 						clr_cfg_state(pif);
1482 						return (-1);
1483 					}
1484 				}
1485 			}
1486 
1487 			/* Last module is the device driver, so ignore that */
1488 			for (i = (lif->li_modcnt - 2); i > 0; i--) {
1489 				rcm_log_message(RCM_TRACE2,
1490 				    "IP: modremove Pos = %d, Module = %s \n",
1491 				    i, lif->li_modules[i]);
1492 				if (modop(pif->pi_ifname, lif->li_modules[i],
1493 				    i, MOD_REMOVE) == -1) {
1494 					while (i != (lif->li_modcnt - 2)) {
1495 						if (modop(pif->pi_ifname,
1496 						    lif->li_modules[i],
1497 						    i, MOD_INSERT) == -1) {
1498 							/* Gross error */
1499 							rcm_log_message(
1500 							    RCM_ERROR,
1501 							    _("IP: if_cfginfo"
1502 							    "(%s) %s\n"),
1503 							    pif->pi_ifname,
1504 							    strerror(errno));
1505 							clr_cfg_state(pif);
1506 							return (-1);
1507 						}
1508 						i++;
1509 					}
1510 					rcm_log_message(
1511 					    RCM_ERROR,
1512 					    _("IP: if_cfginfo(%s): modremove "
1513 					    "%s failed: %s\n"), pif->pi_ifname,
1514 					    lif->li_modules[i],
1515 					    strerror(errno));
1516 					clr_cfg_state(pif);
1517 					return (-1);
1518 				}
1519 			}
1520 		}
1521 
1522 		/* Save reconfiguration information */
1523 		if (lif->li_ifflags & IFF_IPV4) {
1524 			(void) snprintf(syscmd, sizeof (syscmd),
1525 			    "%s %s:%d configinfo\n", SBIN_IFCONFIG,
1526 			    pif->pi_ifname, lif->li_ifnum);
1527 		} else if (lif->li_ifflags & IFF_IPV6) {
1528 			(void) snprintf(syscmd, sizeof (syscmd),
1529 			    "%s %s:%d inet6 configinfo\n", SBIN_IFCONFIG,
1530 			    pif->pi_ifname, lif->li_ifnum);
1531 		}
1532 		rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd);
1533 
1534 		/* open a pipe to retrieve reconfiguration info */
1535 		if ((fp = popen(syscmd, "r")) == NULL) {
1536 			rcm_log_message(RCM_ERROR,
1537 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1538 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
1539 			clr_cfg_state(pif);
1540 			return (-1);
1541 		}
1542 		bzero(buf, MAX_RECONFIG_SIZE);
1543 
1544 		if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) {
1545 			rcm_log_message(RCM_ERROR,
1546 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1547 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
1548 			(void) pclose(fp);
1549 			clr_cfg_state(pif);
1550 			return (-1);
1551 		}
1552 		(void) pclose(fp);
1553 
1554 		if ((lif->li_reconfig = strdup(buf)) == NULL) {
1555 			rcm_log_message(RCM_ERROR,
1556 			    _("IP: malloc error (%s) %s\n"),
1557 			    pif->pi_ifname, strerror(errno));
1558 			clr_cfg_state(pif);
1559 			return (-1);
1560 		}
1561 		rcm_log_message(RCM_DEBUG,
1562 		    "IP: if_cfginfo: reconfig string(%s:%d) = %s\n",
1563 		    pif->pi_ifname, lif->li_ifnum, lif->li_reconfig);
1564 
1565 		lif = lif->li_next;
1566 	}
1567 
1568 	return (0);
1569 }
1570 
1571 /*
1572  * if_unplumb() - Unplumb the interface
1573  *		Save off the modlist, ifconfig options and unplumb.
1574  *		Fail, if an unknown module lives between IP and driver and
1575  *		force is not set
1576  *		Call with cache_lock held
1577  */
1578 static int
1579 if_unplumb(ip_cache_t *node)
1580 {
1581 	ip_lif_t *lif;
1582 	ip_pif_t *pif = node->ip_pif;
1583 	boolean_t ipv4 = B_FALSE;
1584 	boolean_t ipv6 = B_FALSE;
1585 
1586 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource);
1587 
1588 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1589 		if (lif->li_ifflags & IFF_IPV4) {
1590 			ipv4 = B_TRUE;
1591 		} else if (lif->li_ifflags & IFF_IPV6) {
1592 			ipv6 = B_TRUE;
1593 		} else {
1594 			/* Unlikely case */
1595 			rcm_log_message(RCM_DEBUG,
1596 			    "IP: Unplumb ignored (%s:%d)\n",
1597 			    pif->pi_ifname, lif->li_ifnum);
1598 		}
1599 	}
1600 
1601 	if (ipv4 && !ifconfig(pif->pi_ifname, "inet", "unplumb", B_FALSE)) {
1602 		rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
1603 		    pif->pi_ifname, strerror(errno));
1604 		return (-1);
1605 	}
1606 
1607 	if (ipv6 && !ifconfig(pif->pi_ifname, "inet6", "unplumb", B_FALSE)) {
1608 		rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
1609 		    pif->pi_ifname, strerror(errno));
1610 		return (-1);
1611 	}
1612 
1613 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n",
1614 	    node->ip_resource);
1615 
1616 	return (0);
1617 }
1618 
1619 /*
1620  * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface
1621  *		instances and the logical interfaces in order, restoring
1622  *		all ifconfig options
1623  *		Call with cache_lock held
1624  */
1625 static int
1626 if_replumb(ip_cache_t *node)
1627 {
1628 	ip_lif_t *lif;
1629 	ip_pif_t *pif;
1630 	int i;
1631 	boolean_t success, ipmp;
1632 	const char *fstr;
1633 	char lifname[LIFNAMSIZ];
1634 	char buf[MAX_RECONFIG_SIZE];
1635 	int max_lifnum = 0;
1636 
1637 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource);
1638 
1639 	/*
1640 	 * Be extra careful about bringing up the interfaces in the
1641 	 * correct order:
1642 	 * - First plumb in the physical interface instances
1643 	 * - modinsert the necessary modules@pos
1644 	 * - Next, add the logical interfaces being careful about
1645 	 *   the order, (follow the cached interface number li_ifnum order)
1646 	 */
1647 
1648 	pif = node->ip_pif;
1649 	ipmp = (node->ip_pif->pi_grname[0] != '\0');
1650 
1651 	/*
1652 	 * Make a first pass to plumb in physical interfaces and get a count
1653 	 * of the max logical interfaces
1654 	 */
1655 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1656 		max_lifnum = MAX(lif->li_ifnum, max_lifnum);
1657 		if (lif->li_ifflags & IFF_IPV4) {
1658 			fstr = "inet";
1659 		} else if (lif->li_ifflags & IFF_IPV6) {
1660 			fstr = "inet6";
1661 		} else {
1662 			/* Unlikely case */
1663 			rcm_log_message(RCM_DEBUG,
1664 			    "IP: Re-plumb ignored (%s:%d)\n",
1665 			    pif->pi_ifname, lif->li_ifnum);
1666 			continue;
1667 		}
1668 
1669 		/* ignore logical interface instances */
1670 		if (lif->li_ifnum != 0)
1671 			continue;
1672 
1673 		if ((lif->li_ifflags & IFF_NOFAILOVER) || !ipmp) {
1674 			success = ifconfig("", "", lif->li_reconfig, B_FALSE);
1675 		} else {
1676 			(void) snprintf(buf, sizeof (buf), "plumb group %s",
1677 			    pif->pi_grname);
1678 			success = ifconfig(pif->pi_ifname, fstr, buf, B_FALSE);
1679 		}
1680 
1681 		if (!success) {
1682 			rcm_log_message(RCM_ERROR,
1683 			    _("IP: Cannot plumb (%s) %s\n"), pif->pi_ifname,
1684 			    strerror(errno));
1685 			return (-1);
1686 		}
1687 
1688 		/*
1689 		 * Restart DHCP if necessary.
1690 		 */
1691 		if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1692 		    !ifconfig(pif->pi_ifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1693 			rcm_log_message(RCM_ERROR, _("IP: Cannot start DHCP "
1694 			    "(%s) %s\n"), pif->pi_ifname, strerror(errno));
1695 			return (-1);
1696 		}
1697 
1698 		rcm_log_message(RCM_TRACE2,
1699 		    "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt);
1700 		/* modinsert modules in order, ignore driver(last) */
1701 		for (i = 0; i < (lif->li_modcnt - 1); i++) {
1702 			rcm_log_message(RCM_TRACE2,
1703 			    "IP: modinsert: Pos = %d Mod = %s\n",
1704 			    i, lif->li_modules[i]);
1705 			if (modop(pif->pi_ifname, lif->li_modules[i], i,
1706 			    MOD_INSERT) == -1) {
1707 				rcm_log_message(RCM_ERROR,
1708 				    _("IP: modinsert error(%s)\n"),
1709 				    pif->pi_ifname);
1710 				return (-1);
1711 			}
1712 		}
1713 	}
1714 
1715 	/* Now, add all the logical interfaces in the correct order */
1716 	for (i = 1; i <= max_lifnum; i++) {
1717 		(void) snprintf(lifname, LIFNAMSIZ, "%s:%d", pif->pi_ifname, i);
1718 
1719 		/* reset lif through every iteration */
1720 		for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1721 			/*
1722 			 * Process entries in order.  If the interface is
1723 			 * using IPMP, only process test addresses.
1724 			 */
1725 			if (lif->li_ifnum != i ||
1726 			    (ipmp && !(lif->li_ifflags & IFF_NOFAILOVER)))
1727 				continue;
1728 
1729 			if (!ifconfig("", "", lif->li_reconfig, B_FALSE)) {
1730 				rcm_log_message(RCM_ERROR,
1731 				    _("IP: Cannot addif (%s) %s\n"), lifname,
1732 				    strerror(errno));
1733 				return (-1);
1734 			}
1735 
1736 			/*
1737 			 * Restart DHCP if necessary.
1738 			 */
1739 			if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1740 			    !ifconfig(lifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1741 				rcm_log_message(RCM_ERROR,
1742 				    _("IP: Cannot start DHCP (%s) %s\n"),
1743 				    lifname, strerror(errno));
1744 				return (-1);
1745 			}
1746 		}
1747 	}
1748 
1749 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n",
1750 	    node->ip_resource);
1751 
1752 	return (0);
1753 }
1754 
1755 /*
1756  * clr_cfg_state() - Cleanup after errors in unplumb
1757  */
1758 static void
1759 clr_cfg_state(ip_pif_t *pif)
1760 {
1761 	ip_lif_t *lif;
1762 	int i;
1763 
1764 	lif = pif->pi_lifs;
1765 
1766 	while (lif != NULL) {
1767 		lif->li_modcnt = 0;
1768 		free(lif->li_reconfig);
1769 		lif->li_reconfig = NULL;
1770 		for (i = 0; i < IP_MAX_MODS; i++) {
1771 			free(lif->li_modules[i]);
1772 			lif->li_modules[i] = NULL;
1773 		}
1774 		lif = lif->li_next;
1775 	}
1776 }
1777 
1778 /*
1779  * Attempt to offline ip_cache_t `node'; returns an IPMP error code.
1780  */
1781 static int
1782 ip_ipmp_offline(ip_cache_t *node)
1783 {
1784 	int retval;
1785 	ipmp_handle_t handle;
1786 
1787 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n");
1788 
1789 	if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
1790 		rcm_log_message(RCM_ERROR,
1791 		    _("IP: cannot create ipmp handle: %s\n"),
1792 		    ipmp_errmsg(retval));
1793 		return (retval);
1794 	}
1795 
1796 	retval = ipmp_offline(handle, node->ip_pif->pi_ifname, node->ip_ifred);
1797 	if (retval != IPMP_SUCCESS) {
1798 		rcm_log_message(RCM_ERROR, _("IP: ipmp_offline error: %s\n"),
1799 		    ipmp_errmsg(retval));
1800 	} else {
1801 		rcm_log_message(RCM_TRACE1, "IP: ipmp_offline success\n");
1802 	}
1803 
1804 	ipmp_close(handle);
1805 	return (retval);
1806 }
1807 
1808 /*
1809  * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code.
1810  */
1811 static int
1812 ip_ipmp_undo_offline(ip_cache_t *node)
1813 {
1814 	int retval;
1815 	ipmp_handle_t handle;
1816 
1817 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_undo_offline\n");
1818 
1819 	if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
1820 		rcm_log_message(RCM_ERROR,
1821 		    _("IP: cannot create ipmp handle: %s\n"),
1822 		    ipmp_errmsg(retval));
1823 		return (retval);
1824 	}
1825 
1826 	retval = ipmp_undo_offline(handle, node->ip_pif->pi_ifname);
1827 	if (retval != IPMP_SUCCESS) {
1828 		rcm_log_message(RCM_ERROR,
1829 		    _("IP: ipmp_undo_offline error: %s\n"),
1830 		    ipmp_errmsg(retval));
1831 	} else {
1832 		rcm_log_message(RCM_TRACE1, "IP: ipmp_undo_offline success\n");
1833 	}
1834 
1835 	ipmp_close(handle);
1836 	return (retval);
1837 }
1838 
1839 /*
1840  * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a
1841  * dynamically allocated string containing the associated link resource
1842  * name ("SUNW_datalink/<linkid>").
1843  */
1844 static char *
1845 get_link_resource(const char *link)
1846 {
1847 	char		errmsg[DLADM_STRSIZE];
1848 	datalink_id_t	linkid;
1849 	uint32_t	flags;
1850 	char		*resource;
1851 	dladm_status_t	status;
1852 
1853 	status = dladm_name2info(dld_handle, link, &linkid, &flags, NULL, NULL);
1854 	if (status != DLADM_STATUS_OK)
1855 		goto fail;
1856 
1857 	if (!(flags & DLADM_OPT_ACTIVE)) {
1858 		status = DLADM_STATUS_FAILED;
1859 		goto fail;
1860 	}
1861 
1862 	resource = malloc(RCM_LINK_RESOURCE_MAX);
1863 	if (resource == NULL) {
1864 		rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"),
1865 		    strerror(errno), link);
1866 		return (NULL);
1867 	}
1868 
1869 	(void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u",
1870 	    RCM_LINK_PREFIX, linkid);
1871 
1872 	return (resource);
1873 
1874 fail:
1875 	rcm_log_message(RCM_ERROR,
1876 	    _("IP: get_link_resource for %s error(%s)\n"),
1877 	    link, dladm_status2str(status, errmsg));
1878 	return (NULL);
1879 }
1880 
1881 /*
1882  * modop() - Remove/insert a module
1883  */
1884 static int
1885 modop(char *name, char *arg, int pos, char op)
1886 {
1887 	char syscmd[LIFNAMSIZ+MAXPATHLEN];	/* must be big enough */
1888 
1889 	rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name);
1890 
1891 	/* Nothing to do with "ip", "arp" */
1892 	if ((arg == NULL) || (strcmp(arg, "") == 0) ||
1893 	    STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) {
1894 		rcm_log_message(RCM_TRACE1, "IP: modop success\n");
1895 		return (0);
1896 	}
1897 
1898 	if (op == MOD_CHECK) {
1899 		/*
1900 		 * No known good modules (yet) apart from ip and arp
1901 		 * which are handled above
1902 		 */
1903 		return (-1);
1904 	}
1905 
1906 	if (op == MOD_REMOVE) {
1907 		(void) snprintf(syscmd, sizeof (syscmd),
1908 		    "%s %s modremove %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
1909 	} else if (op == MOD_INSERT) {
1910 		(void) snprintf(syscmd, sizeof (syscmd),
1911 		    "%s %s modinsert %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
1912 	} else {
1913 		rcm_log_message(RCM_ERROR,
1914 		    _("IP: modop(%s): unknown operation\n"), name);
1915 		return (-1);
1916 	}
1917 
1918 	rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd);
1919 	if (rcm_exec_cmd(syscmd) == -1) {
1920 		rcm_log_message(RCM_ERROR,
1921 		    _("IP: modop(%s): %s\n"), name, strerror(errno));
1922 		return (-1);
1923 	}
1924 
1925 	rcm_log_message(RCM_TRACE1, "IP: modop success\n");
1926 	return (0);
1927 }
1928 
1929 /*
1930  * get_modlist() - return a list of pushed mid-stream modules
1931  *		 Required memory is malloced to construct the list,
1932  *		 Caller must free this memory list
1933  *		 Call with cache_lock held
1934  */
1935 static int
1936 get_modlist(char *name, ip_lif_t *lif)
1937 {
1938 	int mux_fd;
1939 	int muxid_fd;
1940 	int fd;
1941 	int i;
1942 	int num_mods;
1943 	struct lifreq lifr;
1944 	struct str_list strlist = { 0 };
1945 
1946 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name);
1947 
1948 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1949 	lifr.lifr_flags = lif->li_ifflags;
1950 	if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) {
1951 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name);
1952 		return (-1);
1953 	}
1954 
1955 	if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) {
1956 		rcm_log_message(RCM_ERROR,
1957 		    _("IP: get_modlist(%s): I_LIST(%s) \n"),
1958 		    name, strerror(errno));
1959 		goto fail;
1960 	}
1961 
1962 	strlist.sl_nmods = num_mods;
1963 	strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods);
1964 	if (strlist.sl_modlist == NULL) {
1965 		rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"),
1966 		    name, strerror(errno));
1967 		goto fail;
1968 	}
1969 
1970 	if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
1971 		rcm_log_message(RCM_ERROR,
1972 		    _("IP: get_modlist(%s): I_LIST error: %s\n"),
1973 		    name, strerror(errno));
1974 		goto fail;
1975 	}
1976 
1977 	for (i = 0; i < strlist.sl_nmods; i++) {
1978 		lif->li_modules[i] = strdup(strlist.sl_modlist[i].l_name);
1979 		if (lif->li_modules[i] == NULL) {
1980 			rcm_log_message(RCM_ERROR,
1981 			    _("IP: get_modlist(%s): %s\n"),
1982 			    name, strerror(errno));
1983 			while (i > 0)
1984 				free(lif->li_modules[--i]);
1985 			goto fail;
1986 		}
1987 	}
1988 
1989 	lif->li_modcnt = strlist.sl_nmods;
1990 	free(strlist.sl_modlist);
1991 
1992 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name);
1993 	return (ip_plink(mux_fd, muxid_fd, fd, &lifr));
1994 fail:
1995 	free(strlist.sl_modlist);
1996 	(void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
1997 	return (-1);
1998 }
1999 
2000 /*
2001  * ip_domux2fd() - Helper function for mod*() functions
2002  *		 Stolen from ifconfig.c
2003  */
2004 static int
2005 ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr)
2006 {
2007 	int muxid_fd;
2008 	char	*udp_dev_name;
2009 
2010 	if (lifr->lifr_flags & IFF_IPV6) {
2011 		udp_dev_name  = UDP6_DEV_NAME;
2012 	} else {
2013 		udp_dev_name  = UDP_DEV_NAME;
2014 	}
2015 
2016 	if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) {
2017 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2018 		    udp_dev_name, strerror(errno));
2019 		return (-1);
2020 	}
2021 	if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) {
2022 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2023 		    udp_dev_name, strerror(errno));
2024 		(void) close(muxid_fd);
2025 		return (-1);
2026 	}
2027 	if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) {
2028 		rcm_log_message(RCM_ERROR,
2029 		    _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"),
2030 		    udp_dev_name, strerror(errno));
2031 		(void) close(*mux_fd);
2032 		(void) close(muxid_fd);
2033 		return (-1);
2034 	}
2035 
2036 	rcm_log_message(RCM_TRACE2,
2037 	    "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n",
2038 	    lifr->lifr_arp_muxid, lifr->lifr_ip_muxid);
2039 
2040 	if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) {
2041 		rcm_log_message(RCM_ERROR,
2042 		    _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"),
2043 		    udp_dev_name, strerror(errno));
2044 		(void) close(*mux_fd);
2045 		(void) close(muxid_fd);
2046 		return (-1);
2047 	}
2048 	if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) {
2049 		rcm_log_message(RCM_ERROR,
2050 		    _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"),
2051 		    udp_dev_name, strerror(errno));
2052 		(void) close(*mux_fd);
2053 		(void) close(muxid_fd);
2054 		return (-1);
2055 	}
2056 
2057 	/* Note: mux_fd and muxid_fd are closed in ip_plink below */
2058 	*muxid_fdp = muxid_fd;
2059 	return (0);
2060 }
2061 
2062 /*
2063  * ip_plink() - Helper function for mod*() functions.
2064  *	      Stolen from ifconfig.c
2065  */
2066 static int
2067 ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr)
2068 {
2069 	int mux_id;
2070 
2071 	if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) {
2072 		rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"),
2073 		    UDP_DEV_NAME, strerror(errno));
2074 		(void) close(mux_fd);
2075 		(void) close(muxid_fd);
2076 		(void) close(fd);
2077 		return (-1);
2078 	}
2079 
2080 	lifr->lifr_ip_muxid = mux_id;
2081 	if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) {
2082 		rcm_log_message(RCM_ERROR,
2083 		    _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"),
2084 		    UDP_DEV_NAME, strerror(errno));
2085 		(void) close(mux_fd);
2086 		(void) close(muxid_fd);
2087 		(void) close(fd);
2088 		return (-1);
2089 	}
2090 
2091 	(void) close(mux_fd);
2092 	(void) close(muxid_fd);
2093 	(void) close(fd);
2094 	return (0);
2095 }
2096 
2097 /*
2098  * ip_onlinelist()
2099  *
2100  *	Notify online to IP address consumers.
2101  */
2102 /*ARGSUSED*/
2103 static int
2104 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2105 		rcm_info_t **depend_info)
2106 {
2107 	char **addrlist;
2108 	int ret = RCM_SUCCESS;
2109 
2110 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n");
2111 
2112 	addrlist = ip_get_addrlist(node);
2113 	if (addrlist == NULL || addrlist[0] == NULL) {
2114 		rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n");
2115 		ip_free_addrlist(addrlist);
2116 		return (ret);
2117 	}
2118 
2119 	ret = rcm_notify_online_list(hd, addrlist, 0, depend_info);
2120 
2121 	ip_free_addrlist(addrlist);
2122 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n");
2123 	return (ret);
2124 }
2125 
2126 /*
2127  * ip_offlinelist()
2128  *
2129  *	Offline IP address consumers.
2130  */
2131 /*ARGSUSED*/
2132 static int
2133 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2134 	rcm_info_t **depend_info)
2135 {
2136 	char **addrlist;
2137 	int ret = RCM_SUCCESS;
2138 
2139 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n");
2140 
2141 	addrlist = ip_get_addrlist(node);
2142 	if (addrlist == NULL || addrlist[0] == NULL) {
2143 		rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n");
2144 		ip_free_addrlist(addrlist);
2145 		return (RCM_SUCCESS);
2146 	}
2147 
2148 	if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info))
2149 	    != RCM_SUCCESS) {
2150 		if (ret == RCM_FAILURE)
2151 			(void) rcm_notify_online_list(hd, addrlist, 0, NULL);
2152 
2153 		ret = RCM_FAILURE;
2154 	}
2155 
2156 	ip_free_addrlist(addrlist);
2157 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n");
2158 	return (ret);
2159 }
2160 
2161 /*
2162  * ip_get_addrlist() -	Get the list of IP addresses on this interface (node);
2163  *			This routine malloc()s required memory for the list.
2164  *			Returns the list on success, NULL on failure.
2165  *			Call with cache_lock held.
2166  */
2167 static char **
2168 ip_get_addrlist(ip_cache_t *node)
2169 {
2170 	ip_lif_t *lif;
2171 	char **addrlist = NULL;
2172 	int i, numifs;
2173 	size_t addrlistsize;
2174 	char addrstr[INET6_ADDRSTRLEN];
2175 
2176 	rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n",
2177 	    node->ip_resource);
2178 
2179 	numifs = 0;
2180 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
2181 		numifs++;
2182 	}
2183 
2184 	/*
2185 	 * Allocate space for resource names list; add 1 and use calloc()
2186 	 * so that the list is NULL-terminated.
2187 	 */
2188 	if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) {
2189 		rcm_log_message(RCM_ERROR,
2190 		    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2191 		    node->ip_resource, strerror(errno));
2192 		return (NULL);
2193 	}
2194 
2195 	for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL;
2196 	    lif = lif->li_next, i++) {
2197 
2198 		if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) {
2199 			ip_free_addrlist(addrlist);
2200 			return (NULL);
2201 		}
2202 
2203 		addrlistsize = strlen(addrstr) + sizeof (RCM_STR_SUNW_IP);
2204 		if ((addrlist[i] = malloc(addrlistsize)) == NULL) {
2205 			rcm_log_message(RCM_ERROR,
2206 			    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2207 			    node->ip_resource, strerror(errno));
2208 			ip_free_addrlist(addrlist);
2209 			return (NULL);
2210 		}
2211 		(void) snprintf(addrlist[i], addrlistsize, "%s%s",
2212 		    RCM_STR_SUNW_IP, addrstr);
2213 
2214 		rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]);
2215 	}
2216 
2217 	rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n",
2218 	    node->ip_resource);
2219 
2220 	return (addrlist);
2221 }
2222 
2223 static void
2224 ip_free_addrlist(char **addrlist)
2225 {
2226 	int i;
2227 
2228 	if (addrlist == NULL)
2229 		return;
2230 
2231 	for (i = 0; addrlist[i] != NULL; i++)
2232 		free(addrlist[i]);
2233 	free(addrlist);
2234 }
2235 
2236 /*
2237  * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
2238  */
2239 
2240 static void
2241 ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
2242     uint_t flags, rcm_info_t **depend_info)
2243 {
2244 	char cached_name[RCM_LINK_RESOURCE_MAX];
2245 	ip_cache_t *node;
2246 
2247 	assert(linkid != DATALINK_INVALID_LINKID);
2248 
2249 	rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid);
2250 
2251 	/* Check for the interface in the cache */
2252 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2253 	    RCM_LINK_PREFIX, linkid);
2254 
2255 	(void) mutex_lock(&cache_lock);
2256 	if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) {
2257 		rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"),
2258 		    linkid);
2259 		(void) mutex_unlock(&cache_lock);
2260 		return;
2261 	}
2262 	/*
2263 	 * Inform anonymous consumers about IP addresses being onlined.
2264 	 */
2265 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
2266 
2267 	(void) mutex_unlock(&cache_lock);
2268 
2269 	rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n");
2270 }
2271 
2272 /*
2273  * if_configure() - Configure a physical interface after attach
2274  */
2275 static int
2276 if_configure(datalink_id_t linkid)
2277 {
2278 	char ifinst[MAXLINKNAMELEN];
2279 	char cfgfile[MAXPATHLEN];
2280 	char cached_name[RCM_LINK_RESOURCE_MAX];
2281 	FILE *hostfp, *host6fp;
2282 	ip_cache_t *node;
2283 	boolean_t ipmp = B_FALSE;
2284 
2285 	assert(linkid != DATALINK_INVALID_LINKID);
2286 	rcm_log_message(RCM_TRACE1, _("IP: if_configure(%u)\n"), linkid);
2287 
2288 	/* Check for the interface in the cache */
2289 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2290 	    RCM_LINK_PREFIX, linkid);
2291 
2292 	/* Check if the interface is new or was not previously offlined */
2293 	(void) mutex_lock(&cache_lock);
2294 	if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) &&
2295 	    (!(node->ip_cachestate & CACHE_IF_OFFLINED))) {
2296 		rcm_log_message(RCM_TRACE1,
2297 		    _("IP: Skipping configured interface(%u)\n"), linkid);
2298 		(void) mutex_unlock(&cache_lock);
2299 		return (0);
2300 	}
2301 	(void) mutex_unlock(&cache_lock);
2302 
2303 	if (dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, NULL, ifinst,
2304 	    sizeof (ifinst)) != DLADM_STATUS_OK) {
2305 		rcm_log_message(RCM_ERROR,
2306 		    _("IP: get %u link name failed\n"), linkid);
2307 		return (-1);
2308 	}
2309 
2310 	/*
2311 	 * Scan the IPv4 and IPv6 hostname files to see if (a) they exist
2312 	 * and (b) if either one places the interface into an IPMP group.
2313 	 */
2314 	(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifinst);
2315 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2316 	if ((hostfp = fopen(cfgfile, "r")) != NULL) {
2317 		if (isgrouped(cfgfile))
2318 			ipmp = B_TRUE;
2319 	}
2320 
2321 	(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifinst);
2322 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2323 	if ((host6fp = fopen(cfgfile, "r")) != NULL) {
2324 		if (!ipmp && isgrouped(cfgfile))
2325 			ipmp = B_TRUE;
2326 	}
2327 
2328 	/*
2329 	 * Configure the interface according to its hostname files.
2330 	 */
2331 	if (hostfp != NULL &&
2332 	    if_config_inst(ifinst, hostfp, AF_INET, ipmp) == -1) {
2333 		rcm_log_message(RCM_ERROR,
2334 		    _("IP: IPv4 Post-attach failed (%s)\n"), ifinst);
2335 		goto fail;
2336 	}
2337 
2338 	if (host6fp != NULL &&
2339 	    if_config_inst(ifinst, host6fp, AF_INET6, ipmp) == -1) {
2340 		rcm_log_message(RCM_ERROR,
2341 		    _("IP: IPv6 Post-attach failed (%s)\n"), ifinst);
2342 		goto fail;
2343 	}
2344 
2345 	(void) fclose(hostfp);
2346 	(void) fclose(host6fp);
2347 	rcm_log_message(RCM_TRACE1, "IP: if_configure(%s) success\n", ifinst);
2348 	return (0);
2349 fail:
2350 	(void) fclose(hostfp);
2351 	(void) fclose(host6fp);
2352 	return (-1);
2353 }
2354 
2355 /*
2356  * isgrouped() - Scans the given config file to see if this interface is
2357  *	         using IPMP.  Returns B_TRUE or B_FALSE.
2358  */
2359 static boolean_t
2360 isgrouped(const char *cfgfile)
2361 {
2362 	FILE *fp;
2363 	struct stat statb;
2364 	char *nlp, *line, *token, *lasts, *buf;
2365 	boolean_t grouped = B_FALSE;
2366 
2367 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile);
2368 
2369 	if (stat(cfgfile, &statb) != 0) {
2370 		rcm_log_message(RCM_TRACE1,
2371 		    _("IP: No config file(%s)\n"), cfgfile);
2372 		return (B_FALSE);
2373 	}
2374 
2375 	/*
2376 	 * We also ignore single-byte config files because the file should
2377 	 * always be newline-terminated, so we know there's nothing of
2378 	 * interest.  Further, a single-byte file would cause the fgets() loop
2379 	 * below to spin forever.
2380 	 */
2381 	if (statb.st_size <= 1) {
2382 		rcm_log_message(RCM_TRACE1,
2383 		    _("IP: Empty config file(%s)\n"), cfgfile);
2384 		return (B_FALSE);
2385 	}
2386 
2387 	if ((fp = fopen(cfgfile, "r")) == NULL) {
2388 		rcm_log_message(RCM_ERROR,
2389 		    _("IP: Cannot open configuration file(%s): %s\n"), cfgfile,
2390 		    strerror(errno));
2391 		return (B_FALSE);
2392 	}
2393 
2394 	if ((buf = malloc(statb.st_size)) == NULL) {
2395 		rcm_log_message(RCM_ERROR,
2396 		    _("IP: malloc failure(%s): %s\n"), cfgfile,
2397 		    strerror(errno));
2398 		goto out;
2399 	}
2400 
2401 	while (fgets(buf, statb.st_size, fp) != NULL) {
2402 		if ((nlp = strrchr(buf, '\n')) != NULL)
2403 			*nlp = '\0';
2404 
2405 		line = buf;
2406 		while ((token = strtok_r(line, " \t", &lasts)) != NULL) {
2407 			line = NULL;
2408 			if (STREQ("group", token) &&
2409 			    strtok_r(NULL, " \t", &lasts) != NULL) {
2410 				grouped = B_TRUE;
2411 				goto out;
2412 			}
2413 		}
2414 	}
2415 out:
2416 	free(buf);
2417 	(void) fclose(fp);
2418 
2419 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s): %d\n", cfgfile,
2420 	    grouped);
2421 
2422 	return (grouped);
2423 }
2424 
2425 /*
2426  * if_config_inst() - Configure an interface instance as specified by the
2427  *		    address family af and if it is grouped (ipmp).
2428  */
2429 static int
2430 if_config_inst(const char *ifinst, FILE *hfp, int af, boolean_t ipmp)
2431 {
2432 	FILE *ifparsefp;
2433 	struct stat statb;
2434 	char *buf = NULL;
2435 	char *ifparsebuf = NULL;
2436 	uint_t ifparsebufsize;
2437 	const char *fstr;		/* address family string */
2438 	boolean_t stdif = B_FALSE;
2439 
2440 	rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) ipmp = %d\n",
2441 	    ifinst, ipmp);
2442 
2443 	if (fstat(fileno(hfp), &statb) != 0) {
2444 		rcm_log_message(RCM_ERROR,
2445 		    _("IP: Cannot fstat file(%s)\n"), ifinst);
2446 		goto fail;
2447 	}
2448 
2449 	switch (af) {
2450 	case AF_INET:
2451 		fstr = "inet";
2452 		break;
2453 	case AF_INET6:
2454 		fstr = "inet6";
2455 		break;
2456 	default:
2457 		assert(0);
2458 	}
2459 
2460 	/*
2461 	 * The hostname file exists; plumb the physical interface.
2462 	 */
2463 	if (!ifconfig(ifinst, fstr, "plumb", B_FALSE))
2464 		goto fail;
2465 
2466 	/* Skip static configuration if the hostname file is empty */
2467 	if (statb.st_size <= 1) {
2468 		rcm_log_message(RCM_TRACE1,
2469 		    _("IP: Zero size hostname file(%s)\n"), ifinst);
2470 		goto configured;
2471 	}
2472 
2473 	if (fseek(hfp, 0, SEEK_SET) == -1) {
2474 		rcm_log_message(RCM_ERROR,
2475 		    _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2476 		    strerror(errno));
2477 		goto fail;
2478 	}
2479 
2480 	/*
2481 	 * Allocate the worst-case single-line buffer sizes.  A bit skanky,
2482 	 * but since hostname files are small, this should suffice.
2483 	 */
2484 	if ((buf = calloc(1, statb.st_size)) == NULL) {
2485 		rcm_log_message(RCM_ERROR,
2486 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2487 		goto fail;
2488 	}
2489 
2490 	ifparsebufsize = statb.st_size + sizeof (SBIN_IFPARSE " -s inet6 ");
2491 	if ((ifparsebuf = calloc(1, ifparsebufsize)) == NULL) {
2492 		rcm_log_message(RCM_ERROR,
2493 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2494 		goto fail;
2495 	}
2496 
2497 	/*
2498 	 * For IPv4, determine whether the hostname file consists of a single
2499 	 * line.  We need to handle these specially since they should
2500 	 * automatically be suffixed with "netmask + broadcast + up".
2501 	 */
2502 	if (af == AF_INET &&
2503 	    fgets(buf, statb.st_size, hfp) != NULL &&
2504 	    fgets(buf, statb.st_size, hfp) == NULL) {
2505 		rcm_log_message(RCM_TRACE1, "IP: one-line hostname file\n");
2506 		stdif = B_TRUE;
2507 	}
2508 
2509 	if (fseek(hfp, 0L, SEEK_SET) == -1) {
2510 		rcm_log_message(RCM_ERROR,
2511 		    _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2512 		    strerror(errno));
2513 		goto fail;
2514 	}
2515 
2516 	/*
2517 	 * Loop through the file one line at a time and feed it to ifconfig.
2518 	 * If the interface is using IPMP, then we use /sbin/ifparse -s to
2519 	 * weed out all of the data addresses, since those are already on the
2520 	 * IPMP meta-interface.
2521 	 */
2522 	while (fgets(buf, statb.st_size, hfp) != NULL) {
2523 		if (ntok(buf) == 0)
2524 			continue;
2525 
2526 		if (!ipmp) {
2527 			(void) ifconfig(ifinst, fstr, buf, stdif);
2528 			continue;
2529 		}
2530 
2531 		(void) snprintf(ifparsebuf, ifparsebufsize, SBIN_IFPARSE
2532 		    " -s %s %s", fstr, buf);
2533 		if ((ifparsefp = popen(ifparsebuf, "r")) == NULL) {
2534 			rcm_log_message(RCM_ERROR,
2535 			    _("IP: cannot configure %s: popen \"%s\" "
2536 			    "failed: %s\n"), ifinst, buf, strerror(errno));
2537 			goto fail;
2538 		}
2539 
2540 		while (fgets(buf, statb.st_size, ifparsefp) != NULL) {
2541 			if (ntok(buf) > 0)
2542 				(void) ifconfig(ifinst, fstr, buf, stdif);
2543 		}
2544 
2545 		if (pclose(ifparsefp) == -1) {
2546 			rcm_log_message(RCM_ERROR,
2547 			    _("IP: cannot configure %s: pclose \"%s\" "
2548 			    "failed: %s\n"), ifinst, buf, strerror(errno));
2549 			goto fail;
2550 		}
2551 	}
2552 
2553 configured:
2554 	/*
2555 	 * Bring up the interface (it may already be up)
2556 	 *
2557 	 * Technically, since the boot scripts only unconditionally bring up
2558 	 * IPv6 interfaces, we should only unconditionally bring up IPv6 here.
2559 	 * However, if we don't bring up IPv4, and a legacy IPMP configuration
2560 	 * without test addresses is being used, we will never bring the
2561 	 * interface up even though we would've at boot.  One fix is to check
2562 	 * if the IPv4 hostname file contains data addresses that we would've
2563 	 * brought up, but there's no simple way to do that.  Given that it's
2564 	 * rare to have persistent IP configuration for an interface that
2565 	 * leaves it down, we cheap out and always bring it up for IPMP.
2566 	 */
2567 	if ((af == AF_INET6 || ipmp) && !ifconfig(ifinst, fstr, "up", B_FALSE))
2568 		goto fail;
2569 
2570 	/*
2571 	 * For IPv4, if a DHCP configuration file exists, have DHCP configure
2572 	 * the interface.  As with the boot scripts, this is done after the
2573 	 * hostname files are processed so that configuration in those files
2574 	 * (such as IPMP group names) will be applied first.
2575 	 */
2576 	if (af == AF_INET) {
2577 		char dhcpfile[MAXPATHLEN];
2578 		char *dhcpbuf;
2579 		off_t i, dhcpsize;
2580 
2581 		(void) snprintf(dhcpfile, MAXPATHLEN, DHCPFILE_FMT, ifinst);
2582 		if (stat(dhcpfile, &statb) == -1)
2583 			goto out;
2584 
2585 		if ((dhcpbuf = copylist(dhcpfile, &dhcpsize)) == NULL) {
2586 			rcm_log_message(RCM_ERROR, _("IP: cannot read "
2587 			    "(%s): %s\n"), dhcpfile, strerror(errno));
2588 			goto fail;
2589 		}
2590 
2591 		/*
2592 		 * The copylist() API converts \n's to \0's, but we want them
2593 		 * to be spaces.
2594 		 */
2595 		if (dhcpsize > 0) {
2596 			for (i = 0; i < dhcpsize; i++)
2597 				if (dhcpbuf[i] == '\0')
2598 					dhcpbuf[i] = ' ';
2599 			dhcpbuf[dhcpsize - 1] = '\0';
2600 		}
2601 		(void) ifconfig(ifinst, CFG_DHCP_CMD, dhcpbuf, B_FALSE);
2602 		free(dhcpbuf);
2603 	}
2604 out:
2605 	free(ifparsebuf);
2606 	free(buf);
2607 	rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) success\n", ifinst);
2608 	return (0);
2609 fail:
2610 	free(ifparsebuf);
2611 	free(buf);
2612 	rcm_log_message(RCM_ERROR, "IP: if_config_inst(%s) failure\n", ifinst);
2613 	return (-1);
2614 }
2615 
2616 /*
2617  * ntok() - count the number of tokens in the provided buffer.
2618  */
2619 static uint_t
2620 ntok(const char *cp)
2621 {
2622 	uint_t ntok = 0;
2623 
2624 	for (;;) {
2625 		while (ISSPACE(*cp))
2626 			cp++;
2627 
2628 		if (ISEOL(*cp))
2629 			break;
2630 
2631 		do {
2632 			cp++;
2633 		} while (!ISSPACE(*cp) && !ISEOL(*cp));
2634 
2635 		ntok++;
2636 	}
2637 	return (ntok);
2638 }
2639 
2640 static boolean_t
2641 ifconfig(const char *ifinst, const char *fstr, const char *buf, boolean_t stdif)
2642 {
2643 	char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
2644 	int status;
2645 
2646 	(void) snprintf(syscmd, sizeof (syscmd), SBIN_IFCONFIG " %s %s %s",
2647 	    ifinst, fstr, buf);
2648 
2649 	if (stdif)
2650 		(void) strlcat(syscmd, CFG_CMDS_STD, sizeof (syscmd));
2651 
2652 	rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd);
2653 	if ((status = rcm_exec_cmd(syscmd)) != 0) {
2654 		if (WIFEXITED(status)) {
2655 			rcm_log_message(RCM_ERROR, _("IP: \"%s\" failed with "
2656 			    "exit status %d\n"), syscmd, WEXITSTATUS(status));
2657 		} else {
2658 			rcm_log_message(RCM_ERROR, _("IP: Error: %s: %s\n"),
2659 			    syscmd, strerror(errno));
2660 		}
2661 		return (B_FALSE);
2662 	}
2663 	return (B_TRUE);
2664 }
2665