xref: /titanic_44/usr/src/cmd/rcm_daemon/common/ip_rcm.c (revision a576ab5b6e08c47732b3dedca9eaa8a8cbb85720)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This RCM module adds support to the RCM framework for IP managed
30  * interfaces.
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <assert.h>
37 #include <string.h>
38 #include <synch.h>
39 #include <libintl.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/socket.h>
45 #include <sys/sockio.h>
46 #include <net/if.h>
47 #include <netinet/in.h>
48 #include <netinet/tcp.h>
49 #include <arpa/inet.h>
50 #include <stropts.h>
51 #include <strings.h>
52 #include <libdevinfo.h>
53 #include <sys/systeminfo.h>
54 #include <netdb.h>
55 #include <inet/ip.h>
56 #include <libinetutil.h>
57 #include <libdllink.h>
58 
59 #include <ipmp_mpathd.h>
60 #include "rcm_module.h"
61 
62 /*
63  * Definitions
64  */
65 #ifndef lint
66 #define	_(x)	gettext(x)
67 #else
68 #define	_(x)	x
69 #endif
70 
71 /* Some generic well-knowns and defaults used in this module */
72 #define	ARP_MOD_NAME		"arp"		/* arp module */
73 #define	IP_MAX_MODS		9		/* max modules pushed on intr */
74 #define	MAX_RECONFIG_SIZE	1024		/* Max. reconfig string size */
75 
76 #define	RCM_LINK_PREFIX		"SUNW_datalink"	/* RCM datalink name prefix */
77 #define	RCM_LINK_RESOURCE_MAX	(13 + LINKID_STR_WIDTH)
78 
79 #define	RCM_STR_SUNW_IP		"SUNW_ip/"	/* IP address export prefix */
80 #define	RCM_SIZE_SUNW_IP	9		/* strlen("SUNW_ip/") + 1 */
81 
82 /* ifconfig(1M) */
83 #define	USR_SBIN_IFCONFIG	"/usr/sbin/ifconfig" /* ifconfig command */
84 #define	CFGFILE_FMT_IPV4	"/etc/hostname."  /* IPV4 config file */
85 #define	CFGFILE_FMT_IPV6	"/etc/hostname6." /* IPV6 config file */
86 #define	CFG_CMDS_STD	" netmask + broadcast + up" /* Normal config string */
87 #define	CONFIG_AF_INET		0x1		/* Post-configure IPv4 */
88 #define	CONFIG_AF_INET6		0x2		/* Post-configure IPv6 */
89 #define	MAXLINE			1024		/* Max. line length */
90 #define	MAXARGS			512		/* Max. args in ifconfig cmd */
91 
92 /* Physical interface flags mask */
93 #define	RCM_PIF_FLAGS		(IFF_OFFLINE | IFF_INACTIVE | IFF_FAILED | \
94 				    IFF_STANDBY)
95 
96 /* Some useful macros */
97 #ifndef MAX
98 #define	MAX(a, b)	(((a) > (b))?(a):(b))
99 #endif /* MAX */
100 
101 #ifndef ISSPACE
102 #define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
103 #endif
104 
105 #ifndef	ISEOL
106 #define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
107 #endif
108 
109 #ifndef	STREQ
110 #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
111 #endif
112 
113 #ifndef ADDSPACE
114 #define	ADDSPACE(a)	((void) strcat((a), " "))
115 #endif
116 
117 /* Interface Cache state flags */
118 #define	CACHE_IF_STALE		0x1		/* stale cached data */
119 #define	CACHE_IF_NEW		0x2		/* new cached interface */
120 #define	CACHE_IF_OFFLINED	0x4		/* interface offlined */
121 #define	CACHE_IF_IGNORE		0x8		/* state held elsewhere */
122 
123 /* Network Cache lookup options */
124 #define	CACHE_NO_REFRESH	0x1		/* cache refresh not needed */
125 #define	CACHE_REFRESH		0x2		/* refresh cache */
126 
127 /* RCM IPMP Module specific property definitions */
128 #define	RCM_IPMP_MIN_REDUNDANCY	1		/* default min. redundancy */
129 
130 /* in.mpathd(1M) specifics */
131 #define	MPATHD_MAX_RETRIES	5	/* Max. offline retries */
132 
133 /* Stream module operations */
134 #define	MOD_INSERT		0	/* Insert a mid-stream module */
135 #define	MOD_REMOVE		1	/* Remove a mid-stream module */
136 #define	MOD_CHECK		2	/* Check mid-stream module safety */
137 
138 /*
139  * in.mpathd(1M) message passing formats
140  */
141 typedef struct mpathd_cmd {
142 	uint32_t	cmd_command;		/* message command */
143 	char		cmd_ifname[LIFNAMSIZ];	/* this interface name */
144 	char		cmd_movetoif[LIFNAMSIZ]; /* move to interface */
145 	uint32_t	cmd_min_red;		/* min. redundancy */
146 /* Message passing values for MI_SETOINDEX */
147 #define	from_lifname	cmd_ifname		/* current logical interface */
148 #define	to_pifname	cmd_movetoif		/* new physical interface */
149 #define	addr_family	cmd_min_red		/* address family */
150 } mpathd_cmd_t;
151 
152 /* This is needed since mpathd checks message size for offline */
153 typedef struct mpathd_unoffline {
154 	uint32_t	cmd_command;		/* offline / undo offline */
155 	char		cmd_ifname[LIFNAMSIZ];	/* this interface name */
156 } mpathd_unoffline_t;
157 
158 typedef struct mpathd_response {
159 	uint32_t	resp_sys_errno;		/* system errno */
160 	uint32_t	resp_mpathd_err;	/* mpathd error information */
161 } mpathd_response_t;
162 
163 /*
164  * IP module data types
165  */
166 
167 /* Physical interface representation */
168 typedef struct ip_pif {
169 	char			pi_ifname[LIFNAMSIZ+1];	/* interface name */
170 	char			pi_grpname[LIFNAMSIZ+1]; /* IPMP group name */
171 	struct ip_lif		*pi_lifs;	/* ptr to logical interfaces */
172 } ip_pif_t;
173 
174 /* Logical interface representation */
175 typedef struct ip_lif
176 {
177 	struct ip_lif		*li_next;	/* ptr to next lif */
178 	struct ip_lif		*li_prev;  	/* previous next ptr */
179 	ip_pif_t		*li_pif;	/* back ptr to phy int */
180 	ushort_t		li_ifnum;	/* interface number */
181 	union {
182 		sa_family_t		family;
183 		struct sockaddr_storage storage;
184 		struct sockaddr_in	ip4;    /* IPv4 */
185 		struct sockaddr_in6	ip6;    /* IPv6 */
186 	} li_addr;
187 	uint64_t		li_ifflags;	/* current IFF_* flags */
188 	int			li_modcnt;	/* # of modules */
189 	char	*li_modules[IP_MAX_MODS];	/* module list pushed */
190 	char	*li_reconfig;			/* Reconfiguration string */
191 	int32_t			li_cachestate;	/* cache state flags */
192 } ip_lif_t;
193 
194 /* Cache element */
195 typedef struct ip_cache
196 {
197 	struct ip_cache		*ip_next;	/* next cached resource */
198 	struct ip_cache		*ip_prev;	/* prev cached resource */
199 	char			*ip_resource;	/* resource name */
200 	ip_pif_t		*ip_pif;	/* ptr to phy int */
201 	int32_t			ip_ifred;	/* min. redundancy */
202 	int			ip_cachestate;	/* cache state flags */
203 } ip_cache_t;
204 
205 /*
206  * Global cache for network interfaces
207  */
208 static ip_cache_t	cache_head;
209 static ip_cache_t	cache_tail;
210 static mutex_t		cache_lock;
211 static int		events_registered = 0;
212 
213 /*
214  * RCM module interface prototypes
215  */
216 static int ip_register(rcm_handle_t *);
217 static int ip_unregister(rcm_handle_t *);
218 static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t,
219 			char **, char **, nvlist_t *, rcm_info_t **);
220 static int ip_suspend(rcm_handle_t *, char *, id_t,
221 			timespec_t *, uint_t, char **, rcm_info_t **);
222 static int ip_resume(rcm_handle_t *, char *, id_t, uint_t,
223 			char **, rcm_info_t **);
224 static int ip_offline(rcm_handle_t *, char *, id_t, uint_t,
225 			char **, rcm_info_t **);
226 static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
227 			char **, rcm_info_t **);
228 static int ip_remove(rcm_handle_t *, char *, id_t, uint_t,
229 			char **, rcm_info_t **);
230 static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t,
231 			char **, nvlist_t *, rcm_info_t **);
232 
233 /* Module private routines */
234 static void 	free_cache();
235 static int 	update_cache(rcm_handle_t *);
236 static void 	cache_remove(ip_cache_t *);
237 static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char);
238 static void 	free_node(ip_cache_t *);
239 static void 	cache_insert(ip_cache_t *);
240 static char 	*ip_usage(ip_cache_t *);
241 static int 	update_pif(rcm_handle_t *, int, int, struct lifreq *);
242 static int 	ip_ipmp_offline(ip_cache_t *, ip_cache_t *);
243 static int	ip_ipmp_undo_offline(ip_cache_t *);
244 static int	if_cfginfo(ip_cache_t *, uint_t);
245 static int	if_unplumb(ip_cache_t *);
246 static int	if_replumb(ip_cache_t *);
247 static void 	ip_log_err(ip_cache_t *, char **, char *);
248 static char	*get_link_resource(const char *);
249 static void	clr_cfg_state(ip_pif_t *);
250 static uint64_t	if_get_flags(ip_pif_t *);
251 static int	mpathd_send_cmd(mpathd_cmd_t *);
252 static int	connect_to_mpathd(int);
253 static int	modop(char *, char *, int, char);
254 static int	get_modlist(char *, ip_lif_t *);
255 static int	ip_domux2fd(int *, int *, int *, struct lifreq *);
256 static int	ip_plink(int, int, int, struct lifreq *);
257 static int	ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
258 			rcm_info_t **);
259 static int	ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
260 			rcm_info_t **);
261 static char 	**ip_get_addrlist(ip_cache_t *);
262 static void	ip_free_addrlist(char **);
263 static void	ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **,
264 			uint_t, rcm_info_t **);
265 
266 static int if_configure(datalink_id_t);
267 static int isgrouped(char *);
268 static int if_ipmp_config(char *, int, int);
269 static int if_mpathd_configure(char *, char *, int, int);
270 static char *get_mpathd_dest(char *, int);
271 static int if_getcount(int);
272 static void tokenize(char *, char **, char *, int *);
273 
274 
275 /* Module-Private data */
276 static struct rcm_mod_ops ip_ops =
277 {
278 	RCM_MOD_OPS_VERSION,
279 	ip_register,
280 	ip_unregister,
281 	ip_get_info,
282 	ip_suspend,
283 	ip_resume,
284 	ip_offline,
285 	ip_undo_offline,
286 	ip_remove,
287 	NULL,
288 	NULL,
289 	ip_notify_event
290 };
291 
292 /*
293  * rcm_mod_init() - Update registrations, and return the ops structure.
294  */
295 struct rcm_mod_ops *
296 rcm_mod_init(void)
297 {
298 	rcm_log_message(RCM_TRACE1, "IP: mod_init\n");
299 
300 	cache_head.ip_next = &cache_tail;
301 	cache_head.ip_prev = NULL;
302 	cache_tail.ip_prev = &cache_head;
303 	cache_tail.ip_next = NULL;
304 	(void) mutex_init(&cache_lock, NULL, NULL);
305 
306 	/* Return the ops vectors */
307 	return (&ip_ops);
308 }
309 
310 /*
311  * rcm_mod_info() - Return a string describing this module.
312  */
313 const char *
314 rcm_mod_info(void)
315 {
316 	rcm_log_message(RCM_TRACE1, "IP: mod_info\n");
317 
318 	return ("IP Multipathing module version %I%");
319 }
320 
321 /*
322  * rcm_mod_fini() - Destroy the network interfaces cache.
323  */
324 int
325 rcm_mod_fini(void)
326 {
327 	rcm_log_message(RCM_TRACE1, "IP: mod_fini\n");
328 
329 	free_cache();
330 	(void) mutex_destroy(&cache_lock);
331 	return (RCM_SUCCESS);
332 }
333 
334 /*
335  * ip_register() - Make sure the cache is properly sync'ed, and its
336  *		 registrations are in order.
337  */
338 static int
339 ip_register(rcm_handle_t *hd)
340 {
341 	rcm_log_message(RCM_TRACE1, "IP: register\n");
342 
343 	/* Guard against bad arguments */
344 	assert(hd != NULL);
345 
346 	if (update_cache(hd) < 0)
347 		return (RCM_FAILURE);
348 
349 	/*
350 	 * Need to register interest in all new resources
351 	 * getting attached, so we get attach event notifications
352 	 */
353 	if (!events_registered) {
354 		if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
355 		    != RCM_SUCCESS) {
356 			rcm_log_message(RCM_ERROR,
357 			    _("IP: failed to register %s\n"),
358 			    RCM_RESOURCE_LINK_NEW);
359 			return (RCM_FAILURE);
360 		} else {
361 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
362 			    RCM_RESOURCE_LINK_NEW);
363 			events_registered++;
364 		}
365 	}
366 
367 	return (RCM_SUCCESS);
368 }
369 
370 /*
371  * ip_unregister() - Walk the cache, unregistering all the networks.
372  */
373 static int
374 ip_unregister(rcm_handle_t *hd)
375 {
376 	ip_cache_t *probe;
377 
378 	rcm_log_message(RCM_TRACE1, "IP: unregister\n");
379 
380 	/* Guard against bad arguments */
381 	assert(hd != NULL);
382 
383 	/* Walk the cache, unregistering everything */
384 	(void) mutex_lock(&cache_lock);
385 	probe = cache_head.ip_next;
386 	while (probe != &cache_tail) {
387 		if (rcm_unregister_interest(hd, probe->ip_resource, 0)
388 		    != RCM_SUCCESS) {
389 			/* unregister failed for whatever reason */
390 			(void) mutex_unlock(&cache_lock);
391 			return (RCM_FAILURE);
392 		}
393 		cache_remove(probe);
394 		free_node(probe);
395 		probe = cache_head.ip_next;
396 	}
397 	(void) mutex_unlock(&cache_lock);
398 
399 	/*
400 	 * Need to unregister interest in all new resources
401 	 */
402 	if (events_registered) {
403 		if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
404 		    != RCM_SUCCESS) {
405 			rcm_log_message(RCM_ERROR,
406 			    _("IP: failed to unregister %s\n"),
407 			    RCM_RESOURCE_LINK_NEW);
408 			return (RCM_FAILURE);
409 		} else {
410 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
411 			    RCM_RESOURCE_LINK_NEW);
412 			events_registered--;
413 		}
414 	}
415 
416 	return (RCM_SUCCESS);
417 }
418 
419 /*
420  * ip_offline() - Offline an interface.
421  */
422 static int
423 ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
424     char **errorp, rcm_info_t **depend_info)
425 {
426 	ip_cache_t *node;
427 	ip_pif_t *pif;
428 	int detachable = 0;
429 	int nofailover = 0;
430 	int ipmp = 0;
431 
432 	rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc);
433 
434 	/* Guard against bad arguments */
435 	assert(hd != NULL);
436 	assert(rsrc != NULL);
437 	assert(id == (id_t)0);
438 	assert(errorp != NULL);
439 	assert(depend_info != NULL);
440 
441 	/* Lock the cache and lookup the resource */
442 	(void) mutex_lock(&cache_lock);
443 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
444 	if (node == NULL) {
445 		ip_log_err(node, errorp, "Unrecognized resource");
446 		errno = ENOENT;
447 		(void) mutex_unlock(&cache_lock);
448 		return (RCM_SUCCESS);
449 	}
450 
451 	pif = node->ip_pif;
452 
453 	/* Establish default detachability criteria */
454 	if (flags & RCM_FORCE) {
455 		detachable++;
456 	}
457 
458 	/* Check if the interface is an IPMP grouped interface */
459 	if (strcmp(pif->pi_grpname, "")) {
460 		ipmp++;
461 	}
462 
463 	if (if_get_flags(pif) & IFF_NOFAILOVER) {
464 		nofailover++;
465 	}
466 
467 	/*
468 	 * Even if the interface is not in an IPMP group, it's possible that
469 	 * it's still okay to offline it as long as there are higher-level
470 	 * failover mechanisms for the addresses it owns (e.g., clustering).
471 	 * In this case, ip_offlinelist() will return RCM_SUCCESS, and we
472 	 * charge on.
473 	 */
474 	if (!ipmp && !detachable) {
475 		/* Inform consumers of IP addresses being offlined */
476 		if (ip_offlinelist(hd, node, errorp, flags, depend_info) ==
477 		    RCM_SUCCESS) {
478 			rcm_log_message(RCM_DEBUG,
479 			    "IP: consumers agree on detach");
480 		} else {
481 			ip_log_err(node, errorp,
482 			    "Device consumers prohibit offline");
483 			(void) mutex_unlock(&cache_lock);
484 			return (RCM_FAILURE);
485 		}
486 	}
487 
488 	/*
489 	 * Cannot remove an IPMP interface if IFF_NOFAILOVER is set.
490 	 */
491 	if (ipmp && nofailover) {
492 		/* Interface is part of an IPMP group, and cannot failover */
493 		ip_log_err(node, errorp, "Failover disabled");
494 		errno = EBUSY;
495 		(void) mutex_unlock(&cache_lock);
496 		return (RCM_FAILURE);
497 	}
498 
499 	/* Check if it's a query */
500 	if (flags & RCM_QUERY) {
501 		rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n",
502 		    rsrc);
503 		(void) mutex_unlock(&cache_lock);
504 		return (RCM_SUCCESS);
505 	}
506 
507 	/* Check detachability, save configuration if detachable */
508 	if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) {
509 		node->ip_cachestate |= CACHE_IF_IGNORE;
510 		rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc);
511 		(void) mutex_unlock(&cache_lock);
512 		return (RCM_SUCCESS);
513 	}
514 
515 	/* standalone detachable device */
516 	if (!ipmp) {
517 		if (if_unplumb(node) < 0) {
518 			ip_log_err(node, errorp,
519 			    "Failed to unplumb the device");
520 
521 			errno = EIO;
522 			(void) mutex_unlock(&cache_lock);
523 			return (RCM_FAILURE);
524 		}
525 
526 		node->ip_cachestate |= CACHE_IF_OFFLINED;
527 		rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc);
528 		(void) mutex_unlock(&cache_lock);
529 		return (RCM_SUCCESS);
530 	}
531 
532 	/*
533 	 * This an IPMP interface that can be failed over.
534 	 * Request in.mpathd(1M) to failover the physical interface.
535 	 */
536 
537 	/* Failover to "any", let mpathd determine best failover candidate */
538 	if (ip_ipmp_offline(node, NULL) < 0) {
539 		ip_log_err(node, errorp, "in.mpathd failover failed");
540 		/*
541 		 * Odds are that in.mpathd(1M) could not offline the device
542 		 * because it was the last interface in the group.  However,
543 		 * it's possible that it's still okay to offline it as long as
544 		 * there are higher-level failover mechanisms for the
545 		 * addresses it owns (e.g., clustering).  In this case,
546 		 * ip_offlinelist() will return RCM_SUCCESS, and we charge on.
547 		 *
548 		 * TODO: change ip_ipmp_offline() to return the actual failure
549 		 * from in.mpathd so that we can verify that it did indeed
550 		 * fail with IPMP_EMINRED.
551 		 */
552 		if (!detachable) {
553 			/* Inform consumers of IP addresses being offlined */
554 			if (ip_offlinelist(hd, node, errorp, flags,
555 			    depend_info) == RCM_SUCCESS) {
556 				rcm_log_message(RCM_DEBUG,
557 				    "IP: consumers agree on detach");
558 			} else {
559 				ip_log_err(node, errorp,
560 				    "Device consumers prohibit offline");
561 				(void) mutex_unlock(&cache_lock);
562 				errno = EBUSY;
563 				return (RCM_FAILURE);
564 			}
565 		}
566 	}
567 
568 	if (if_unplumb(node) < 0) {
569 		rcm_log_message(RCM_ERROR,
570 		    _("IP: Unplumb failed (%s)\n"),
571 		    pif->pi_ifname);
572 
573 		/* Request mpathd to undo the offline */
574 		if (ip_ipmp_undo_offline(node) < 0) {
575 			ip_log_err(node, errorp, "Undo offline failed");
576 			(void) mutex_unlock(&cache_lock);
577 			return (RCM_FAILURE);
578 		}
579 		(void) mutex_unlock(&cache_lock);
580 		return (RCM_FAILURE);
581 	}
582 
583 	node->ip_cachestate |= CACHE_IF_OFFLINED;
584 	rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc);
585 	(void) mutex_unlock(&cache_lock);
586 	return (RCM_SUCCESS);
587 }
588 
589 /*
590  * ip_undo_offline() - Undo offline of a previously offlined device.
591  */
592 /*ARGSUSED*/
593 static int
594 ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
595     char **errorp, rcm_info_t **depend_info)
596 {
597 	ip_cache_t *node;
598 
599 	rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc);
600 
601 	/* Guard against bad arguments */
602 	assert(hd != NULL);
603 	assert(rsrc != NULL);
604 	assert(id == (id_t)0);
605 	assert(errorp != NULL);
606 	assert(depend_info != NULL);
607 
608 	(void) mutex_lock(&cache_lock);
609 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
610 
611 	if (node == NULL) {
612 		ip_log_err(node, errorp, "No such device");
613 		(void) mutex_unlock(&cache_lock);
614 		errno = ENOENT;
615 		return (RCM_FAILURE);
616 	}
617 
618 	/* Check if no attempt should be made to online the device here */
619 	if (node->ip_cachestate & CACHE_IF_IGNORE) {
620 		node->ip_cachestate &= ~(CACHE_IF_IGNORE);
621 		(void) mutex_unlock(&cache_lock);
622 		return (RCM_SUCCESS);
623 	}
624 
625 	/* Check if the interface was previously offlined */
626 	if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) {
627 		ip_log_err(node, errorp, "Device not offlined");
628 		(void) mutex_unlock(&cache_lock);
629 		errno = ENOTSUP;
630 		return (RCM_FAILURE);
631 	}
632 
633 	if (if_replumb(node) == -1) {
634 		/* re-plumb failed */
635 		ip_log_err(node, errorp, "Replumb failed");
636 		(void) mutex_unlock(&cache_lock);
637 		errno = EIO;
638 		return (RCM_FAILURE);
639 
640 	}
641 
642 	/* Inform consumers about IP addresses being un-offlined */
643 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
644 
645 	node->ip_cachestate &= ~(CACHE_IF_OFFLINED);
646 	rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc);
647 	(void) mutex_unlock(&cache_lock);
648 	return (RCM_SUCCESS);
649 }
650 
651 /*
652  * ip_get_info() - Gather usage information for this resource.
653  */
654 /*ARGSUSED*/
655 int
656 ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
657     char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info)
658 {
659 	ip_cache_t *node;
660 	char *infostr;
661 
662 	/* Guard against bad arguments */
663 	assert(hd != NULL);
664 	assert(rsrc != NULL);
665 	assert(id == (id_t)0);
666 	assert(usagep != NULL);
667 	assert(errorp != NULL);
668 	assert(depend_info != NULL);
669 
670 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc);
671 
672 	(void) mutex_lock(&cache_lock);
673 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
674 	if (!node) {
675 		rcm_log_message(RCM_INFO,
676 		    _("IP: get_info(%s) unrecognized resource\n"), rsrc);
677 		(void) mutex_unlock(&cache_lock);
678 		errno = ENOENT;
679 		return (RCM_FAILURE);
680 	}
681 
682 	infostr = ip_usage(node);
683 
684 	if (infostr == NULL) {
685 		/* most likely malloc failure */
686 		rcm_log_message(RCM_ERROR,
687 		    _("IP: get_info(%s) malloc failure\n"), rsrc);
688 		(void) mutex_unlock(&cache_lock);
689 		errno = ENOMEM;
690 		*errorp = NULL;
691 		return (RCM_FAILURE);
692 	}
693 
694 	/* Set client/role properties */
695 	(void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP");
696 
697 	/* Set usage property, infostr will be freed by caller */
698 	*usagep = infostr;
699 
700 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n",
701 	    rsrc, infostr);
702 
703 	(void) mutex_unlock(&cache_lock);
704 	return (RCM_SUCCESS);
705 }
706 
707 /*
708  * ip_suspend() - Nothing to do, always okay
709  */
710 /*ARGSUSED*/
711 static int
712 ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
713 			uint_t flags, char **errorp, rcm_info_t **depend_info)
714 {
715 	/* Guard against bad arguments */
716 	assert(hd != NULL);
717 	assert(rsrc != NULL);
718 	assert(id == (id_t)0);
719 	assert(interval != NULL);
720 	assert(errorp != NULL);
721 	assert(depend_info != NULL);
722 
723 	rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc);
724 	return (RCM_SUCCESS);
725 }
726 
727 /*
728  * ip_resume() - Nothing to do, always okay
729  */
730 /*ARGSUSED*/
731 static int
732 ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
733 		char **errorp, rcm_info_t ** depend_info)
734 {
735 	/* Guard against bad arguments */
736 	assert(hd != NULL);
737 	assert(rsrc != NULL);
738 	assert(id == (id_t)0);
739 	assert(errorp != NULL);
740 	assert(depend_info != NULL);
741 
742 	rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc);
743 
744 	return (RCM_SUCCESS);
745 }
746 
747 /*
748  * ip_remove() - remove a resource from cache
749  */
750 /*ARGSUSED*/
751 static int
752 ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
753 		char **errorp, rcm_info_t **depend_info)
754 {
755 	ip_cache_t *node;
756 
757 	/* Guard against bad arguments */
758 	assert(hd != NULL);
759 	assert(rsrc != NULL);
760 	assert(id == (id_t)0);
761 	assert(errorp != NULL);
762 	assert(depend_info != NULL);
763 
764 	rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc);
765 
766 	(void) mutex_lock(&cache_lock);
767 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
768 	if (!node) {
769 		rcm_log_message(RCM_INFO,
770 		    _("IP: remove(%s) unrecognized resource\n"), rsrc);
771 		(void) mutex_unlock(&cache_lock);
772 		errno = ENOENT;
773 		return (RCM_FAILURE);
774 	}
775 
776 	/* remove the cached entry for the resource */
777 	cache_remove(node);
778 	free_node(node);
779 
780 	(void) mutex_unlock(&cache_lock);
781 	return (RCM_SUCCESS);
782 }
783 
784 /*
785  * ip_notify_event - Project private implementation to receive new resource
786  *		   events. It intercepts all new resource events. If the
787  *		   new resource is a network resource, pass up a notify
788  *		   for it too. The new resource need not be cached, since
789  *		   it is done at register again.
790  */
791 /*ARGSUSED*/
792 static int
793 ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
794 			char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
795 {
796 	datalink_id_t	linkid;
797 	nvpair_t *nvp = NULL;
798 	uint64_t id64;
799 
800 	assert(hd != NULL);
801 	assert(rsrc != NULL);
802 	assert(id == (id_t)0);
803 	assert(nvl != NULL);
804 
805 	rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc);
806 
807 	if (!STREQ(rsrc, RCM_RESOURCE_LINK_NEW)) {
808 		rcm_log_message(RCM_INFO,
809 		    _("IP: unrecognized event for %s\n"), rsrc);
810 		ip_log_err(NULL, errorp, "unrecognized event");
811 		errno = EINVAL;
812 		return (RCM_FAILURE);
813 	}
814 
815 	/* Update cache to reflect latest interfaces */
816 	if (update_cache(hd) < 0) {
817 		rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n"));
818 		ip_log_err(NULL, errorp, "Private Cache update failed");
819 		return (RCM_FAILURE);
820 	}
821 
822 	rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n");
823 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
824 		if (STREQ(nvpair_name(nvp), RCM_NV_LINKID)) {
825 			if (nvpair_value_uint64(nvp, &id64) != 0) {
826 				rcm_log_message(RCM_WARNING,
827 				    _("IP: cannot get linkid\n"));
828 				return (RCM_FAILURE);
829 			}
830 			linkid = (datalink_id_t)id64;
831 			if (if_configure(linkid) != 0) {
832 				rcm_log_message(RCM_ERROR,
833 				    _("IP: Configuration failed (%u)\n"),
834 				    linkid);
835 				ip_log_err(NULL, errorp,
836 				    "Failed configuring one or more IP "
837 				    "addresses");
838 			}
839 
840 			/* Notify all IP address consumers */
841 			ip_consumer_notify(hd, linkid, errorp, flags,
842 			    depend_info);
843 		}
844 	}
845 
846 	rcm_log_message(RCM_TRACE1,
847 	    "IP: notify_event: device configuration complete\n");
848 
849 	return (RCM_SUCCESS);
850 }
851 
852 /*
853  * ip_usage - Determine the usage of a device.  Call with cache_lock held.
854  *	    The returned buffer is owned by caller, and the caller
855  *	    must free it up when done.
856  */
857 static char *
858 ip_usage(ip_cache_t *node)
859 {
860 	ip_lif_t *lif;
861 	int numifs;
862 	char *buf;
863 	char *linkidstr;
864 	datalink_id_t linkid;
865 	const char *fmt;
866 	char *sep;
867 	char link[MAXLINKNAMELEN];
868 	char addrstr[INET6_ADDRSTRLEN];
869 	char errmsg[DLADM_STRSIZE];
870 	dladm_status_t status;
871 	int offline = 0;
872 	size_t bufsz;
873 
874 	rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource);
875 
876 	/*
877 	 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid>
878 	 */
879 	linkidstr = strchr(node->ip_resource, '/');
880 	assert(linkidstr != NULL);
881 	linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource;
882 
883 	errno = 0;
884 	linkid = strtol(linkidstr, &buf, 10);
885 	if (errno != 0 || *buf != '\0') {
886 		rcm_log_message(RCM_ERROR,
887 		    _("IP: usage(%s) parse linkid failure (%s)\n"),
888 		    node->ip_resource, strerror(errno));
889 		return (NULL);
890 	}
891 
892 	if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link,
893 	    sizeof (link))) != DLADM_STATUS_OK) {
894 		rcm_log_message(RCM_ERROR,
895 		    _("IP: usage(%s) get link name failure(%s)\n"),
896 		    node->ip_resource, dladm_status2str(status, errmsg));
897 		return (NULL);
898 	}
899 
900 	/* TRANSLATION_NOTE: separator used between IP addresses */
901 	sep = _(", ");
902 
903 	numifs = 0;
904 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
905 		if (lif->li_ifflags & IFF_UP) {
906 			numifs++;
907 		}
908 	}
909 
910 	if (node->ip_cachestate & CACHE_IF_OFFLINED) {
911 		offline++;
912 	}
913 
914 	if (!offline && numifs) {
915 		fmt = _("%1$s hosts IP addresses: ");
916 	} else if (offline) {
917 		fmt = _("%1$s offlined");
918 	} else {
919 		fmt = _("%1$s plumbed but down");
920 	}
921 
922 	/* space for addresses and separators, plus message */
923 	bufsz = ((numifs * (INET6_ADDRSTRLEN + strlen(sep))) +
924 	    strlen(fmt) + strlen(link) + 1);
925 	if ((buf = malloc(bufsz)) == NULL) {
926 		rcm_log_message(RCM_ERROR,
927 		    _("IP: usage(%s) malloc failure(%s)\n"),
928 		    node->ip_resource, strerror(errno));
929 		return (NULL);
930 	}
931 	bzero(buf, bufsz);
932 	(void) sprintf(buf, fmt, link);
933 
934 	if (offline || (numifs == 0)) {	/* Nothing else to do */
935 		rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
936 		    node->ip_resource, buf);
937 
938 		return (buf);
939 	}
940 
941 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
942 
943 		void *addr;
944 		int af;
945 
946 		if (!(lif->li_ifflags & IFF_UP)) {
947 			/* ignore interfaces not up */
948 			continue;
949 		}
950 		af = lif->li_addr.family;
951 		if (af == AF_INET6) {
952 			addr = &lif->li_addr.ip6.sin6_addr;
953 		} else if (af == AF_INET) {
954 			addr = &lif->li_addr.ip4.sin_addr;
955 		} else {
956 			rcm_log_message(RCM_DEBUG,
957 			    "IP: unknown addr family %d, assuming AF_INET\n",
958 			    af);
959 			af = AF_INET;
960 			addr = &lif->li_addr.ip4.sin_addr;
961 		}
962 		if (inet_ntop(af, addr, addrstr, INET6_ADDRSTRLEN) == NULL) {
963 			rcm_log_message(RCM_ERROR,
964 			    _("IP: inet_ntop: %s\n"), strerror(errno));
965 			continue;
966 		}
967 		rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr);
968 
969 		(void) strcat(buf, addrstr);
970 		numifs--;
971 		if (numifs > 0) {
972 			(void) strcat(buf, ", ");
973 		}
974 	}
975 
976 	rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
977 	    node->ip_resource, buf);
978 
979 	return (buf);
980 }
981 
982 /*
983  * Cache management routines, all cache management functions should be
984  * be called with cache_lock held.
985  */
986 
987 /*
988  * cache_lookup() - Get a cache node for a resource.
989  *		  Call with cache lock held.
990  *
991  * This ensures that the cache is consistent with the system state and
992  * returns a pointer to the cache element corresponding to the resource.
993  */
994 static ip_cache_t *
995 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
996 {
997 	ip_cache_t *probe;
998 
999 	rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc);
1000 
1001 	if ((options & CACHE_REFRESH) && (hd != NULL)) {
1002 		/* drop lock since update locks cache again */
1003 		(void) mutex_unlock(&cache_lock);
1004 		(void) update_cache(hd);
1005 		(void) mutex_lock(&cache_lock);
1006 	}
1007 
1008 	probe = cache_head.ip_next;
1009 	while (probe != &cache_tail) {
1010 		if (probe->ip_resource &&
1011 		    STREQ(rsrc, probe->ip_resource)) {
1012 			rcm_log_message(RCM_TRACE2,
1013 			    "IP: cache lookup success(%s)\n", rsrc);
1014 			return (probe);
1015 		}
1016 		probe = probe->ip_next;
1017 	}
1018 	return (NULL);
1019 }
1020 
1021 /*
1022  * free_node - Free a node from the cache
1023  *	     Call with cache_lock held.
1024  */
1025 static void
1026 free_node(ip_cache_t *node)
1027 {
1028 	ip_pif_t *pif;
1029 	ip_lif_t *lif, *tmplif;
1030 
1031 	if (node) {
1032 		if (node->ip_resource) {
1033 			free(node->ip_resource);
1034 		}
1035 
1036 		/* free the pif */
1037 		pif = node->ip_pif;
1038 		if (pif) {
1039 			/* free logical interfaces */
1040 			lif = pif->pi_lifs;
1041 			while (lif) {
1042 				tmplif = lif->li_next;
1043 				free(lif);
1044 				lif = tmplif;
1045 			}
1046 			free(pif);
1047 		}
1048 		free(node);
1049 	}
1050 }
1051 
1052 /*
1053  * cache_insert - Insert a resource node in cache
1054  *		Call with the cache_lock held.
1055  */
1056 static void
1057 cache_insert(ip_cache_t *node)
1058 {
1059 	rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n",
1060 	    node->ip_resource);
1061 
1062 	/* insert at the head for best performance */
1063 	node->ip_next = cache_head.ip_next;
1064 	node->ip_prev = &cache_head;
1065 
1066 	node->ip_next->ip_prev = node;
1067 	node->ip_prev->ip_next = node;
1068 }
1069 
1070 /*
1071  * cache_remove() - Remove a resource node from cache.
1072  *		  Call with the cache_lock held.
1073  */
1074 static void
1075 cache_remove(ip_cache_t *node)
1076 {
1077 	rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n",
1078 	    node->ip_resource);
1079 
1080 	node->ip_next->ip_prev = node->ip_prev;
1081 	node->ip_prev->ip_next = node->ip_next;
1082 	node->ip_next = NULL;
1083 	node->ip_prev = NULL;
1084 }
1085 
1086 /*
1087  * update_pif() - Update physical interface properties
1088  *		Call with cache_lock held
1089  */
1090 /*ARGSUSED*/
1091 static int
1092 update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
1093 {
1094 	char *rsrc;
1095 	ifspec_t ifspec;
1096 	ushort_t ifnumber = 0;
1097 	ip_cache_t *probe;
1098 	ip_pif_t pif;
1099 	ip_pif_t *probepif;
1100 	ip_lif_t *probelif;
1101 	struct lifreq lifreq;
1102 	struct sockaddr_storage ifaddr;
1103 	uint64_t ifflags;
1104 	int lif_listed = 0;
1105 
1106 	rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", lifr->lifr_name);
1107 
1108 	if (!ifparse_ifspec(lifr->lifr_name, &ifspec)) {
1109 		rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"),
1110 		    lifr->lifr_name);
1111 		return (-1);
1112 	}
1113 
1114 	(void) snprintf(pif.pi_ifname, sizeof (pif.pi_ifname), "%s%d",
1115 	    ifspec.ifsp_devnm, ifspec.ifsp_ppa);
1116 	if (ifspec.ifsp_lunvalid)
1117 		ifnumber = ifspec.ifsp_lun;
1118 
1119 	/* Get the interface flags */
1120 	(void) strcpy(lifreq.lifr_name, lifr->lifr_name);
1121 	if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
1122 		rcm_log_message(RCM_ERROR,
1123 		    _("IP: SIOCGLIFFLAGS(%s): %s\n"),
1124 		    pif.pi_ifname, strerror(errno));
1125 		return (-1);
1126 	}
1127 	(void) memcpy(&ifflags, &lifreq.lifr_flags, sizeof (ifflags));
1128 
1129 	/*
1130 	 * Ignore interfaces that are always incapable of DR:
1131 	 *   - IFF_VIRTUAL:	e.g., loopback and vni
1132 	 *   - IFF_POINTOPOINT:	e.g., sppp and ip.tun
1133 	 *   - !IFF_MULTICAST:	e.g., ip.6to4tun
1134 	 *
1135 	 * Note: The !IFF_MULTICAST check can be removed once iptun is
1136 	 * implemented as a datalink.
1137 	 */
1138 	if (!(ifflags & IFF_MULTICAST) ||
1139 	    (ifflags & (IFF_POINTOPOINT | IFF_VIRTUAL))) {
1140 		rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n",
1141 		    pif.pi_ifname);
1142 		return (0);
1143 	}
1144 
1145 	/* Get the interface group name for this interface */
1146 	if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) {
1147 		rcm_log_message(RCM_ERROR,
1148 		    _("IP: SIOCGLIFGROUPNAME(%s): %s\n"),
1149 		    lifreq.lifr_name, strerror(errno));
1150 		return (-1);
1151 	}
1152 
1153 	/* copy the group name */
1154 	(void) memcpy(&pif.pi_grpname, &lifreq.lifr_groupname,
1155 	    sizeof (pif.pi_grpname));
1156 	pif.pi_grpname[sizeof (pif.pi_grpname) - 1] = '\0';
1157 
1158 	/* Get the interface address for this interface */
1159 	if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) {
1160 		rcm_log_message(RCM_ERROR,
1161 		    _("IP: SIOCGLIFADDR(%s): %s\n"),
1162 		    lifreq.lifr_name, strerror(errno));
1163 		return (-1);
1164 	}
1165 	(void) memcpy(&ifaddr, &lifreq.lifr_addr, sizeof (ifaddr));
1166 
1167 	rsrc = get_link_resource(pif.pi_ifname);
1168 	if (rsrc == NULL) {
1169 		rcm_log_message(RCM_ERROR,
1170 		    _("IP: get_link_resource(%s) failed\n"),
1171 		    lifreq.lifr_name);
1172 		return (-1);
1173 	}
1174 
1175 	probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
1176 	if (probe != NULL) {
1177 		free(rsrc);
1178 		probe->ip_cachestate &= ~(CACHE_IF_STALE);
1179 	} else {
1180 		if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) {
1181 			/* malloc errors are bad */
1182 			free(rsrc);
1183 			rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1184 			    strerror(errno));
1185 			return (-1);
1186 		}
1187 
1188 		probe->ip_resource = rsrc;
1189 		probe->ip_pif = NULL;
1190 		probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY;
1191 		probe->ip_cachestate |= CACHE_IF_NEW;
1192 
1193 		cache_insert(probe);
1194 	}
1195 
1196 	probepif = probe->ip_pif;
1197 	if (probepif != NULL) {
1198 		/* Check if lifs need to be updated */
1199 		probelif = probepif->pi_lifs;
1200 		while (probelif != NULL) {
1201 			if ((probelif->li_ifnum == ifnumber) &&
1202 			    (probelif->li_addr.family == ifaddr.ss_family)) {
1203 
1204 				rcm_log_message(RCM_TRACE2,
1205 				    "IP: refreshing lifs for %s, ifnum=%d\n",
1206 				    pif.pi_ifname, probelif->li_ifnum);
1207 
1208 				/* refresh lif properties */
1209 				(void) memcpy(&probelif->li_addr, &ifaddr,
1210 				    sizeof (probelif->li_addr));
1211 
1212 				probelif->li_ifflags = ifflags;
1213 
1214 				lif_listed++;
1215 				probelif->li_cachestate &= ~(CACHE_IF_STALE);
1216 				break;
1217 			}
1218 			probelif = probelif->li_next;
1219 		}
1220 	}
1221 
1222 	if (probepif == NULL) {
1223 		if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) {
1224 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1225 			    strerror(errno));
1226 			if (probe->ip_pif == NULL) {
1227 				/* we created it, so clean it up */
1228 				free(probe);
1229 			}
1230 			return (-1);
1231 		}
1232 
1233 		probe->ip_pif = probepif;
1234 
1235 		/* Save interface name */
1236 		(void) memcpy(&probepif->pi_ifname, &pif.pi_ifname,
1237 		    sizeof (pif.pi_ifname));
1238 	}
1239 
1240 	/* save pif properties */
1241 	(void) memcpy(&probepif->pi_grpname, &pif.pi_grpname,
1242 	    sizeof (pif.pi_grpname));
1243 
1244 	/* add lif, if this is a lif and it is not in cache */
1245 	if (!lif_listed) {
1246 		rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n",
1247 		    pif.pi_ifname);
1248 
1249 		if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) {
1250 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1251 			    strerror(errno));
1252 			return (-1);
1253 		}
1254 
1255 		/* save lif properties */
1256 		(void) memcpy(&probelif->li_addr, &ifaddr,
1257 		    sizeof (probelif->li_addr));
1258 
1259 		probelif->li_ifnum = ifnumber;
1260 		probelif->li_ifflags = ifflags;
1261 
1262 		/* insert us at the head of the lif list */
1263 		probelif->li_next = probepif->pi_lifs;
1264 		if (probelif->li_next != NULL) {
1265 			probelif->li_next->li_prev = probelif;
1266 		}
1267 		probelif->li_prev = NULL;
1268 		probelif->li_pif = probepif;
1269 
1270 		probepif->pi_lifs = probelif;
1271 	}
1272 
1273 	rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n",
1274 	    probe->ip_resource);
1275 
1276 	return (0);
1277 }
1278 
1279 /*
1280  * update_ipifs() - Determine all network interfaces in the system
1281  *		  Call with cache_lock held
1282  */
1283 static int
1284 update_ipifs(rcm_handle_t *hd, int af)
1285 {
1286 	int sock;
1287 	char *buf;
1288 	struct lifnum lifn;
1289 	struct lifconf lifc;
1290 	struct lifreq *lifrp;
1291 	int i;
1292 
1293 	rcm_log_message(RCM_TRACE2, "IP: update_ipifs\n");
1294 
1295 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
1296 		rcm_log_message(RCM_ERROR,
1297 		    _("IP: failure opening %s socket: %s\n"),
1298 		    af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
1299 		return (-1);
1300 	}
1301 
1302 	lifn.lifn_family = af;
1303 	lifn.lifn_flags = 0;
1304 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
1305 		rcm_log_message(RCM_ERROR,
1306 		    _("IP: SIOCLGIFNUM failed: %s\n"),
1307 		    strerror(errno));
1308 		(void) close(sock);
1309 		return (-1);
1310 	}
1311 
1312 	if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) {
1313 		rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1314 		    strerror(errno));
1315 		(void) close(sock);
1316 		return (-1);
1317 	}
1318 
1319 	lifc.lifc_family = af;
1320 	lifc.lifc_flags = 0;
1321 	lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count;
1322 	lifc.lifc_buf = buf;
1323 
1324 	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
1325 		rcm_log_message(RCM_ERROR,
1326 		    _("IP: SIOCGLIFCONF failed: %s\n"),
1327 		    strerror(errno));
1328 		free(buf);
1329 		(void) close(sock);
1330 		return (-1);
1331 	}
1332 
1333 	/* now we need to search for active interfaces */
1334 	lifrp = lifc.lifc_req;
1335 	for (i = 0; i < lifn.lifn_count; i++) {
1336 		(void) update_pif(hd, af, sock, lifrp);
1337 		lifrp++;
1338 	}
1339 
1340 	free(buf);
1341 	(void) close(sock);
1342 	return (0);
1343 }
1344 
1345 /*
1346  * update_cache() - Update cache with latest interface info
1347  */
1348 static int
1349 update_cache(rcm_handle_t *hd)
1350 {
1351 	ip_cache_t *probe;
1352 	struct ip_lif *lif;
1353 	struct ip_lif *nextlif;
1354 	int rv;
1355 	int i;
1356 
1357 	rcm_log_message(RCM_TRACE2, "IP: update_cache\n");
1358 
1359 	(void) mutex_lock(&cache_lock);
1360 
1361 	/* first we walk the entire cache, marking each entry stale */
1362 	probe = cache_head.ip_next;
1363 	while (probe != &cache_tail) {
1364 		probe->ip_cachestate |= CACHE_IF_STALE;
1365 		if ((probe->ip_pif != NULL) &&
1366 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1367 			while (lif != NULL) {
1368 				lif->li_cachestate |= CACHE_IF_STALE;
1369 				lif = lif->li_next;
1370 			}
1371 		}
1372 		probe = probe->ip_next;
1373 	}
1374 
1375 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n");
1376 	if (update_ipifs(hd, AF_INET) < 0) {
1377 		(void) mutex_unlock(&cache_lock);
1378 		return (-1);
1379 	}
1380 
1381 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n");
1382 	if (update_ipifs(hd, AF_INET6) < 0) {
1383 		(void) mutex_unlock(&cache_lock);
1384 		return (-1);
1385 	}
1386 
1387 	probe = cache_head.ip_next;
1388 	/* unregister devices that are not offlined and still in cache */
1389 	while (probe != &cache_tail) {
1390 		ip_cache_t *freeit;
1391 		if ((probe->ip_pif != NULL) &&
1392 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1393 			/* clear stale lifs */
1394 			while (lif != NULL) {
1395 				if (lif->li_cachestate & CACHE_IF_STALE) {
1396 					nextlif = lif->li_next;
1397 					if (lif->li_prev != NULL)
1398 						lif->li_prev->li_next = nextlif;
1399 					if (nextlif != NULL)
1400 						nextlif->li_prev = lif->li_prev;
1401 					if (probe->ip_pif->pi_lifs == lif)
1402 						probe->ip_pif->pi_lifs =
1403 						    nextlif;
1404 					for (i = 0; i < IP_MAX_MODS; i++) {
1405 						free(lif->li_modules[i]);
1406 					}
1407 					free(lif->li_reconfig);
1408 					free(lif);
1409 					lif = nextlif;
1410 				} else {
1411 					lif = lif->li_next;
1412 				}
1413 			}
1414 		}
1415 		if ((probe->ip_cachestate & CACHE_IF_STALE) &&
1416 		    !(probe->ip_cachestate & CACHE_IF_OFFLINED)) {
1417 			(void) rcm_unregister_interest(hd, probe->ip_resource,
1418 			    0);
1419 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
1420 			    probe->ip_resource);
1421 			freeit = probe;
1422 			probe = probe->ip_next;
1423 			cache_remove(freeit);
1424 			free_node(freeit);
1425 			continue;
1426 		}
1427 
1428 		if (!(probe->ip_cachestate & CACHE_IF_NEW)) {
1429 			probe = probe->ip_next;
1430 			continue;
1431 		}
1432 
1433 		rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL);
1434 		if (rv != RCM_SUCCESS) {
1435 			rcm_log_message(RCM_ERROR,
1436 			    _("IP: failed to register %s\n"),
1437 			    probe->ip_resource);
1438 			(void) mutex_unlock(&cache_lock);
1439 			return (-1);
1440 		} else {
1441 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
1442 			    probe->ip_resource);
1443 			probe->ip_cachestate &= ~(CACHE_IF_NEW);
1444 		}
1445 		probe = probe->ip_next;
1446 	}
1447 
1448 	(void) mutex_unlock(&cache_lock);
1449 	return (0);
1450 }
1451 
1452 /*
1453  * free_cache() - Empty the cache
1454  */
1455 static void
1456 free_cache()
1457 {
1458 	ip_cache_t *probe;
1459 
1460 	rcm_log_message(RCM_TRACE2, "IP: free_cache\n");
1461 
1462 	(void) mutex_lock(&cache_lock);
1463 	probe = cache_head.ip_next;
1464 	while (probe != &cache_tail) {
1465 		cache_remove(probe);
1466 		free_node(probe);
1467 		probe = cache_head.ip_next;
1468 	}
1469 	(void) mutex_unlock(&cache_lock);
1470 }
1471 
1472 /*
1473  * ip_log_err() - RCM error log wrapper
1474  */
1475 static void
1476 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
1477 {
1478 	char *ifname = NULL;
1479 	int len;
1480 	const char *errfmt;
1481 	char *error;
1482 
1483 	if ((node != NULL) && (node->ip_pif != NULL) &&
1484 	    (node->ip_pif->pi_ifname != NULL)) {
1485 		ifname = node->ip_pif->pi_ifname;
1486 	}
1487 
1488 	if (errorp != NULL)
1489 		*errorp = NULL;
1490 
1491 	if (ifname == NULL) {
1492 		rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg);
1493 		errfmt = _("IP: %s");
1494 		len = strlen(errfmt) + strlen(errmsg) + 1;
1495 		if (error = (char *)calloc(1, len)) {
1496 			(void) sprintf(error, errfmt, errmsg);
1497 		}
1498 	} else {
1499 		rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname);
1500 		errfmt = _("IP: %s(%s)");
1501 		len = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1;
1502 		if (error = (char *)calloc(1, len)) {
1503 			(void) sprintf(error, errfmt, errmsg, ifname);
1504 		}
1505 	}
1506 
1507 	if (errorp != NULL)
1508 		*errorp = error;
1509 }
1510 
1511 
1512 /*
1513  * if_cfginfo() - Save off the config info for all interfaces
1514  */
1515 static int
1516 if_cfginfo(ip_cache_t *node, uint_t force)
1517 {
1518 	ip_lif_t *lif;
1519 	ip_pif_t *pif;
1520 	int i;
1521 	FILE *fp;
1522 	char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
1523 	char buf[MAX_RECONFIG_SIZE];
1524 
1525 	rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource);
1526 
1527 	pif = node->ip_pif;
1528 	lif = pif->pi_lifs;
1529 
1530 	while (lif != NULL) {
1531 		/* Make a list of modules pushed and save */
1532 		if (lif->li_ifnum == 0) {	/* physical instance */
1533 			if (get_modlist(pif->pi_ifname, lif) == -1) {
1534 				rcm_log_message(RCM_ERROR,
1535 				    _("IP: get modlist error (%s) %s\n"),
1536 				    pif->pi_ifname, strerror(errno));
1537 				(void) clr_cfg_state(pif);
1538 				return (-1);
1539 			}
1540 
1541 			if (!force) {
1542 				/* Look if unknown modules have been inserted */
1543 				for (i = (lif->li_modcnt - 2); i > 0; i--) {
1544 					if (modop(pif->pi_ifname,
1545 					    lif->li_modules[i],
1546 					    i, MOD_CHECK) == -1) {
1547 						rcm_log_message(RCM_ERROR,
1548 						    _("IP: module %s@%d\n"),
1549 						    lif->li_modules[i], i);
1550 						(void) clr_cfg_state(pif);
1551 						return (-1);
1552 					}
1553 				}
1554 			}
1555 
1556 			/* Last module is the device driver, so ignore that */
1557 			for (i = (lif->li_modcnt - 2); i > 0; i--) {
1558 				rcm_log_message(RCM_TRACE2,
1559 				    "IP: modremove Pos = %d, Module = %s \n",
1560 				    i, lif->li_modules[i]);
1561 				if (modop(pif->pi_ifname, lif->li_modules[i],
1562 				    i, MOD_REMOVE) == -1) {
1563 					while (i != (lif->li_modcnt - 2)) {
1564 						if (modop(pif->pi_ifname,
1565 						    lif->li_modules[i],
1566 						    i, MOD_INSERT) == -1) {
1567 							/* Gross error */
1568 							rcm_log_message(
1569 							    RCM_ERROR,
1570 							    _("IP: if_cfginfo"
1571 							    "(%s) %s\n"),
1572 							    pif->pi_ifname,
1573 							    strerror(errno));
1574 							clr_cfg_state(pif);
1575 							return (-1);
1576 						}
1577 						i++;
1578 					}
1579 					rcm_log_message(
1580 					    RCM_ERROR,
1581 					    _("IP: if_cfginfo(%s): modremove "
1582 					    "%s failed: %s\n"), pif->pi_ifname,
1583 					    lif->li_modules[i],
1584 					    strerror(errno));
1585 					clr_cfg_state(pif);
1586 					return (-1);
1587 				}
1588 			}
1589 		}
1590 
1591 		/* Save reconfiguration information */
1592 		if (lif->li_ifflags & IFF_IPV4) {
1593 			(void) snprintf(syscmd, sizeof (syscmd),
1594 			    "%s %s:%d configinfo\n", USR_SBIN_IFCONFIG,
1595 			    pif->pi_ifname, lif->li_ifnum);
1596 		} else if (lif->li_ifflags & IFF_IPV6) {
1597 			(void) snprintf(syscmd, sizeof (syscmd),
1598 			    "%s %s:%d inet6 configinfo\n", USR_SBIN_IFCONFIG,
1599 			    pif->pi_ifname, lif->li_ifnum);
1600 		}
1601 		rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd);
1602 
1603 		/* open a pipe to retrieve reconfiguration info */
1604 		if ((fp = popen(syscmd, "r")) == NULL) {
1605 			rcm_log_message(RCM_ERROR,
1606 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1607 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
1608 			(void) clr_cfg_state(pif);
1609 			return (-1);
1610 		}
1611 		bzero(buf, MAX_RECONFIG_SIZE);
1612 
1613 		if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) {
1614 			rcm_log_message(RCM_ERROR,
1615 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1616 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
1617 			(void) pclose(fp);
1618 			(void) clr_cfg_state(pif);
1619 			return (-1);
1620 		}
1621 		(void) pclose(fp);
1622 
1623 		lif->li_reconfig = malloc(strlen(buf)+1);
1624 		if (lif->li_reconfig == NULL) {
1625 			rcm_log_message(RCM_ERROR,
1626 			    _("IP: malloc error (%s) %s\n"),
1627 			    pif->pi_ifname, strerror(errno));
1628 			(void) clr_cfg_state(pif);
1629 			return (-1);
1630 		}
1631 		(void) strcpy(lif->li_reconfig, buf);
1632 		rcm_log_message(RCM_DEBUG,
1633 		    "IP: if_cfginfo: reconfig string(%s:%d) = %s\n",
1634 		    pif->pi_ifname, lif->li_ifnum, lif->li_reconfig);
1635 
1636 		lif = lif->li_next;
1637 	}
1638 
1639 	return (0);
1640 }
1641 
1642 /*
1643  * if_unplumb() - Unplumb the interface
1644  *		Save off the modlist, ifconfig options and unplumb.
1645  *		Fail, if an unknown module lives between IP and driver and
1646  *		force is not set
1647  *		Call with cache_lock held
1648  */
1649 static int
1650 if_unplumb(ip_cache_t *node)
1651 {
1652 	ip_lif_t *lif;
1653 	ip_pif_t *pif;
1654 	int ipv4 = 0, ipv6 = 0;
1655 	char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
1656 
1657 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource);
1658 
1659 	pif = node->ip_pif;
1660 	lif = pif->pi_lifs;
1661 
1662 	while (lif != NULL) {
1663 		if (lif->li_ifflags & IFF_IPV4) {
1664 			ipv4++;
1665 		} else if (lif->li_ifflags & IFF_IPV6) {
1666 			ipv6++;
1667 		} else {
1668 			/* Unlikely case */
1669 			rcm_log_message(RCM_DEBUG,
1670 			    "IP: Unplumb ignored (%s:%d)\n",
1671 			    pif->pi_ifname, lif->li_ifnum);
1672 			lif = lif->li_next;
1673 			continue;
1674 		}
1675 		lif = lif->li_next;
1676 	}
1677 
1678 	/* Unplumb the physical interface */
1679 	if (ipv4) {
1680 		rcm_log_message(RCM_TRACE2,
1681 		    "IP: if_unplumb: ifconfig %s unplumb\n", pif->pi_ifname);
1682 		(void) snprintf(syscmd, sizeof (syscmd), "%s %s unplumb\n",
1683 		    USR_SBIN_IFCONFIG, pif->pi_ifname);
1684 		if (rcm_exec_cmd(syscmd) != 0) {
1685 			rcm_log_message(RCM_ERROR,
1686 			    _("IP: Cannot unplumb (%s) %s\n"),
1687 			    pif->pi_ifname, strerror(errno));
1688 			return (-1);
1689 		}
1690 	}
1691 	if (ipv6) {
1692 		rcm_log_message(RCM_TRACE2,
1693 		    "IP: if_unplumb: ifconfig %s inet6 unplumb\n",
1694 		    pif->pi_ifname);
1695 		(void) snprintf(syscmd, sizeof (syscmd),
1696 		    "%s %s inet6 unplumb\n", USR_SBIN_IFCONFIG, pif->pi_ifname);
1697 		if (rcm_exec_cmd(syscmd) != 0) {
1698 			rcm_log_message(RCM_ERROR,
1699 			    _("IP: Cannot unplumb (%s) %s\n"),
1700 			    pif->pi_ifname, strerror(errno));
1701 			return (-1);
1702 		}
1703 	}
1704 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n",
1705 	    node->ip_resource);
1706 
1707 	return (0);
1708 }
1709 
1710 /*
1711  * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface
1712  *		instances and the logical interfaces in order, restoring
1713  *		all ifconfig options
1714  *		Call with cache_lock held
1715  */
1716 static int
1717 if_replumb(ip_cache_t *node)
1718 {
1719 	ip_lif_t *lif;
1720 	ip_pif_t *pif;
1721 	int i;
1722 	char syscmd[LIFNAMSIZ+MAXPATHLEN];	/* must be big enough */
1723 	int max_ipv4 = 0, max_ipv6 = 0;
1724 
1725 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource);
1726 
1727 	/*
1728 	 * Be extra careful about bringing up the interfaces in the
1729 	 * correct order:
1730 	 * - First plumb in the physical interface instances
1731 	 * - modinsert the necessary modules@pos
1732 	 * - Next, add the logical interfaces being careful about
1733 	 *   the order, (follow the cached interface number li_ifnum order)
1734 	 */
1735 
1736 	pif = node->ip_pif;
1737 	lif = pif->pi_lifs;
1738 
1739 	/*
1740 	 * Make a first pass to plumb in physical interfaces and get a count
1741 	 * of the max logical interfaces
1742 	 */
1743 	while (lif != NULL) {
1744 		if (lif->li_ifflags & IFF_IPV4) {
1745 			if (lif->li_ifnum > max_ipv4) {
1746 				max_ipv4 = lif->li_ifnum;
1747 			}
1748 		} else if (lif->li_ifflags & IFF_IPV6) {
1749 			if (lif->li_ifnum > max_ipv6) {
1750 				max_ipv6 = lif->li_ifnum;
1751 			}
1752 		} else {
1753 			/* Unlikely case */
1754 			rcm_log_message(RCM_DEBUG,
1755 			    "IP: Re-plumb ignored (%s:%d)\n",
1756 			    pif->pi_ifname, lif->li_ifnum);
1757 			lif = lif->li_next;
1758 			continue;
1759 		}
1760 
1761 		if (lif->li_ifnum == 0) { /* physical interface instance */
1762 			if ((lif->li_ifflags & IFF_NOFAILOVER) ||
1763 			    (strcmp(pif->pi_grpname, "") == 0)) {
1764 				(void) snprintf(syscmd, sizeof (syscmd),
1765 				    "%s %s\n", USR_SBIN_IFCONFIG,
1766 				    lif->li_reconfig);
1767 			} else if (lif->li_ifflags & IFF_IPV4) {
1768 				(void) snprintf(syscmd, sizeof (syscmd),
1769 				    "%s %s inet plumb group %s\n",
1770 				    USR_SBIN_IFCONFIG,
1771 				    pif->pi_ifname, pif->pi_grpname);
1772 			} else if (lif->li_ifflags & IFF_IPV6) {
1773 				(void) snprintf(syscmd, sizeof (syscmd),
1774 				    "%s %s inet6 plumb group %s\n",
1775 				    USR_SBIN_IFCONFIG,
1776 				    pif->pi_ifname, pif->pi_grpname);
1777 			}
1778 
1779 			rcm_log_message(RCM_TRACE2,
1780 			    "IP: if_replumb: %s\n", syscmd);
1781 			if (rcm_exec_cmd(syscmd) != 0) {
1782 				rcm_log_message(RCM_ERROR,
1783 				    _("IP: Cannot plumb (%s) %s\n"),
1784 				    pif->pi_ifname, strerror(errno));
1785 				return (-1);
1786 			}
1787 
1788 			rcm_log_message(RCM_TRACE2,
1789 			    "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt);
1790 			/* modinsert modules in order, ignore driver(last) */
1791 			for (i = 0; i < (lif->li_modcnt - 1); i++) {
1792 				rcm_log_message(RCM_TRACE2,
1793 				    "IP: modinsert: Pos = %d Mod = %s\n",
1794 				    i, lif->li_modules[i]);
1795 				if (modop(pif->pi_ifname, lif->li_modules[i], i,
1796 				    MOD_INSERT) == -1) {
1797 					rcm_log_message(RCM_ERROR,
1798 					    _("IP: modinsert error(%s)\n"),
1799 					    pif->pi_ifname);
1800 					return (-1);
1801 				}
1802 			}
1803 		}
1804 
1805 		lif = lif->li_next;
1806 	}
1807 
1808 	/* Now, add all the logical interfaces in the correct order */
1809 	for (i = 1; i <= MAX(max_ipv6, max_ipv4); i++) {
1810 		/* reset lif through every iteration */
1811 		lif = pif->pi_lifs;
1812 		while (lif != NULL) {
1813 			if (((lif->li_ifflags & IFF_NOFAILOVER) ||
1814 			    (strcmp(pif->pi_grpname, "") == 0)) &&
1815 			    (lif->li_ifnum == i)) {
1816 				/* Plumb in the logical interface */
1817 				(void) snprintf(syscmd, sizeof (syscmd),
1818 				    "%s %s\n", USR_SBIN_IFCONFIG,
1819 				    lif->li_reconfig);
1820 				rcm_log_message(RCM_TRACE2,
1821 				    "IP: if_replumb: %s\n", syscmd);
1822 				if (rcm_exec_cmd(syscmd) != 0) {
1823 					rcm_log_message(RCM_ERROR,
1824 					    _("IP: Cannot addif (%s:%d) "
1825 					    "%s\n"),
1826 					    pif->pi_ifname, i, strerror(errno));
1827 					return (-1);
1828 				}
1829 			}
1830 			lif = lif->li_next;
1831 		}
1832 	}
1833 
1834 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n",
1835 	    node->ip_resource);
1836 
1837 	return (0);
1838 }
1839 
1840 /*
1841  * clr_cfg_state() - Cleanup after errors in unplumb
1842  */
1843 static void
1844 clr_cfg_state(ip_pif_t *pif)
1845 {
1846 	ip_lif_t *lif;
1847 	int i;
1848 
1849 	lif = pif->pi_lifs;
1850 
1851 	while (lif != NULL) {
1852 		lif->li_modcnt = 0;
1853 		free(lif->li_reconfig);
1854 		lif->li_reconfig = NULL;
1855 		for (i = 0; i < IP_MAX_MODS; i++) {
1856 			free(lif->li_modules[i]);
1857 			lif->li_modules[i] = NULL;
1858 		}
1859 		lif = lif->li_next;
1860 	}
1861 }
1862 
1863 /*
1864  * ip_ipmp_offline() - Failover from if_from to if_to using a
1865  *		     minimum redudancy of min_red. This uses IPMPs
1866  *		     "offline" mechanism to achieve the failover.
1867  */
1868 static int
1869 ip_ipmp_offline(ip_cache_t *if_from, ip_cache_t *if_to)
1870 {
1871 	mpathd_cmd_t mpdcmd;
1872 
1873 	if ((if_from == NULL) || (if_from->ip_pif == NULL) ||
1874 	    (if_from->ip_pif->pi_ifname == NULL)) {
1875 		return (-1);
1876 	}
1877 
1878 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n");
1879 
1880 	mpdcmd.cmd_command = MI_OFFLINE;
1881 	(void) strcpy(mpdcmd.cmd_ifname, if_from->ip_pif->pi_ifname);
1882 
1883 	if ((if_to != NULL) && (if_to->ip_pif != NULL) &&
1884 	    (if_to->ip_pif->pi_ifname != NULL)) {
1885 		rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline (%s)->(%s)\n",
1886 		    if_from->ip_pif->pi_ifname, if_to->ip_pif->pi_ifname);
1887 		(void) strncpy(mpdcmd.cmd_movetoif, if_to->ip_pif->pi_ifname,
1888 		    sizeof (mpdcmd.cmd_movetoif));
1889 		mpdcmd.cmd_movetoif[sizeof (mpdcmd.cmd_movetoif) - 1] = '\0';
1890 	} else {
1891 		rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline (%s)->(any)\n",
1892 		    if_from->ip_pif->pi_ifname);
1893 		(void) strcpy(mpdcmd.cmd_movetoif, "");	/* signifies any */
1894 	}
1895 	mpdcmd.cmd_min_red = if_from->ip_ifred;
1896 
1897 	if (mpathd_send_cmd(&mpdcmd) < 0) {
1898 		rcm_log_message(RCM_ERROR,
1899 		    _("IP: mpathd offline error: %s\n"),
1900 		    strerror(errno));
1901 		return (-1);
1902 	}
1903 
1904 	rcm_log_message(RCM_TRACE1, "IP: ipmp offline success\n");
1905 	return (0);
1906 }
1907 
1908 /*
1909  * ip_ipmp_undo_offline() - Undo prior offline of the interface.
1910  *			  This uses IPMPs "undo offline" feature.
1911  */
1912 static int
1913 ip_ipmp_undo_offline(ip_cache_t *node)
1914 {
1915 	mpathd_cmd_t mpdcmd;
1916 
1917 	mpdcmd.cmd_command = MI_UNDO_OFFLINE;
1918 	(void) strcpy(mpdcmd.cmd_ifname, node->ip_pif->pi_ifname);
1919 
1920 	if (mpathd_send_cmd(&mpdcmd) < 0) {
1921 		rcm_log_message(RCM_ERROR,
1922 		    _("IP: mpathd error: %s\n"),
1923 		    strerror(errno));
1924 		return (-1);
1925 	}
1926 
1927 	rcm_log_message(RCM_TRACE1, "IP: ipmp undo offline success\n");
1928 	return (0);
1929 }
1930 
1931 /*
1932  * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a
1933  * dynamically allocated string containing the associated link resource
1934  * name ("SUNW_datalink/<linkid>").
1935  */
1936 static char *
1937 get_link_resource(const char *link)
1938 {
1939 	char		errmsg[DLADM_STRSIZE];
1940 	datalink_id_t	linkid;
1941 	uint32_t	flags;
1942 	char		*resource;
1943 	dladm_status_t	status;
1944 
1945 	if ((status = dladm_name2info(link, &linkid, &flags, NULL, NULL))
1946 	    != DLADM_STATUS_OK) {
1947 		goto fail;
1948 	}
1949 
1950 	if (!(flags & DLADM_OPT_ACTIVE)) {
1951 		status = DLADM_STATUS_FAILED;
1952 		goto fail;
1953 	}
1954 
1955 	resource = malloc(RCM_LINK_RESOURCE_MAX);
1956 	if (resource == NULL) {
1957 		rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"),
1958 		    strerror(errno), link);
1959 		return (NULL);
1960 	}
1961 
1962 	(void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u",
1963 	    RCM_LINK_PREFIX, linkid);
1964 
1965 	return (resource);
1966 
1967 fail:
1968 	rcm_log_message(RCM_ERROR,
1969 	    _("IP: get_link_resource for %s error(%s)\n"),
1970 	    link, dladm_status2str(status, errmsg));
1971 	return (NULL);
1972 }
1973 
1974 /*
1975  * if_get_flags() - Return the cached physical interface flags
1976  *		  Call with cache_lock held
1977  */
1978 static uint64_t
1979 if_get_flags(ip_pif_t *pif)
1980 {
1981 	ip_lif_t *lif;
1982 
1983 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1984 		if (lif->li_ifnum == 0) {
1985 			return (lif->li_ifflags & RCM_PIF_FLAGS);
1986 		}
1987 	}
1988 	return (0);
1989 }
1990 
1991 /*
1992  * mpathd_send_cmd() - Sends the command to in.mpathd.
1993  */
1994 static int
1995 mpathd_send_cmd(mpathd_cmd_t *mpd)
1996 {
1997 	mpathd_unoffline_t mpc;
1998 	struct mpathd_response mpr;
1999 	int i;
2000 	int s;
2001 
2002 	rcm_log_message(RCM_TRACE1, "IP: mpathd_send_cmd \n");
2003 
2004 	for (i = 0; i < MPATHD_MAX_RETRIES; i++) {
2005 		s = connect_to_mpathd(AF_INET);
2006 		if (s == -1) {
2007 			s = connect_to_mpathd(AF_INET6);
2008 			if (s == -1) {
2009 				rcm_log_message(RCM_ERROR,
2010 				    _("IP: Cannot talk to mpathd\n"));
2011 				return (-1);
2012 			}
2013 		}
2014 		switch (mpd->cmd_command) {
2015 		case MI_OFFLINE :
2016 			rcm_log_message(RCM_TRACE1, "IP: MI_OFFLINE: "
2017 			    "(%s)->(%s) redundancy = %d\n", mpd->cmd_ifname,
2018 			    mpd->cmd_movetoif, mpd->cmd_min_red);
2019 
2020 			if (write(s, mpd, sizeof (mpathd_cmd_t)) !=
2021 			    sizeof (mpathd_cmd_t)) {
2022 				rcm_log_message(RCM_ERROR,
2023 				    _("IP: mpathd write: %s\n"),
2024 				    strerror(errno));
2025 				(void) close(s);
2026 				return (-1);
2027 			}
2028 			break;
2029 
2030 		case MI_SETOINDEX :
2031 			rcm_log_message(RCM_TRACE1, "IP: MI_SETOINDEX: "
2032 			    "(%s)->(%s) family = %d\n", mpd->from_lifname,
2033 			    mpd->to_pifname, mpd->addr_family);
2034 
2035 			if (write(s, mpd, sizeof (mpathd_cmd_t)) !=
2036 			    sizeof (mpathd_cmd_t)) {
2037 				rcm_log_message(RCM_ERROR,
2038 				    _("IP: mpathd write: %s\n"),
2039 				    strerror(errno));
2040 				(void) close(s);
2041 				return (-1);
2042 			}
2043 			break;
2044 
2045 		case MI_UNDO_OFFLINE:
2046 			/* mpathd checks for exact size of the message */
2047 			mpc.cmd_command = mpd->cmd_command;
2048 			(void) strcpy(mpc.cmd_ifname, mpd->cmd_ifname);
2049 
2050 			rcm_log_message(RCM_TRACE1, "IP: MI_UNDO_OFFLINE: "
2051 			    "(%s)\n", mpd->cmd_ifname);
2052 
2053 			if (write(s, &mpc, sizeof (mpathd_unoffline_t)) !=
2054 			    sizeof (mpathd_unoffline_t)) {
2055 				rcm_log_message(RCM_ERROR,
2056 				    _("IP: mpathd write: %s\n"),
2057 				    strerror(errno));
2058 				(void) close(s);
2059 				return (-1);
2060 			}
2061 			break;
2062 		default :
2063 			rcm_log_message(RCM_ERROR,
2064 			    _("IP: unsupported mpathd command\n"));
2065 			(void) close(s);
2066 			return (-1);
2067 		}
2068 
2069 		bzero(&mpr, sizeof (struct mpathd_response));
2070 		/* Read the result from mpathd */
2071 		if (read(s, &mpr, sizeof (struct mpathd_response)) !=
2072 		    sizeof (struct mpathd_response)) {
2073 			rcm_log_message(RCM_ERROR,
2074 			    _("IP: mpathd read : %s\n"), strerror(errno));
2075 			(void) close(s);
2076 			return (-1);
2077 		}
2078 
2079 		(void) close(s);
2080 		if (mpr.resp_mpathd_err == 0) {
2081 			rcm_log_message(RCM_TRACE1,
2082 			    "IP: mpathd_send_cmd success\n");
2083 			return (0);			/* Successful */
2084 		}
2085 
2086 		if (mpr.resp_mpathd_err == MPATHD_SYS_ERROR) {
2087 			if (mpr.resp_sys_errno == EAGAIN) {
2088 				(void) sleep(1);
2089 				rcm_log_message(RCM_DEBUG,
2090 				    "IP: mpathd retrying\n");
2091 				continue;		/* Retry */
2092 			}
2093 			errno = mpr.resp_sys_errno;
2094 			rcm_log_message(RCM_WARNING,
2095 			    _("IP: mpathd_send_cmd error: %s\n"),
2096 			    strerror(errno));
2097 		} else if (mpr.resp_mpathd_err == MPATHD_MIN_RED_ERROR) {
2098 			errno = EIO;
2099 			rcm_log_message(RCM_ERROR, _("IP: in.mpathd(1M): "
2100 			    "Minimum redundancy not met\n"));
2101 		} else {
2102 			rcm_log_message(RCM_ERROR,
2103 			    _("IP: mpathd_send_cmd error\n"));
2104 		}
2105 		/* retry */
2106 	}
2107 
2108 	rcm_log_message(RCM_ERROR,
2109 	    _("IP: mpathd_send_cmd failed %d retries\n"), MPATHD_MAX_RETRIES);
2110 	return (-1);
2111 }
2112 
2113 /*
2114  * Returns -1 on failure. Returns the socket file descriptor on
2115  * success.
2116  */
2117 static int
2118 connect_to_mpathd(int family)
2119 {
2120 	int s;
2121 	struct sockaddr_storage ss;
2122 	struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
2123 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
2124 	struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
2125 	int addrlen;
2126 	int ret;
2127 	int on;
2128 
2129 	rcm_log_message(RCM_TRACE1, "IP: connect_to_mpathd\n");
2130 
2131 	s = socket(family, SOCK_STREAM, 0);
2132 	if (s < 0) {
2133 		rcm_log_message(RCM_ERROR,
2134 		    _("IP: mpathd socket: %s\n"), strerror(errno));
2135 		return (-1);
2136 	}
2137 	bzero((char *)&ss, sizeof (ss));
2138 	ss.ss_family = family;
2139 	/*
2140 	 * Need to bind to a privelged port. For non-root, this
2141 	 * will fail. in.mpathd verifies that only commands coming
2142 	 * from priveleged ports succeed so that the ordinary user
2143 	 * can't issue offline commands.
2144 	 */
2145 	on = 1;
2146 	if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on,
2147 	    sizeof (on)) < 0) {
2148 		rcm_log_message(RCM_ERROR,
2149 		    _("IP: mpathd setsockopt: TCP_ANONPRIVBIND: %s\n"),
2150 		    strerror(errno));
2151 		return (-1);
2152 	}
2153 	switch (family) {
2154 	case AF_INET:
2155 		sin->sin_port = 0;
2156 		sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2157 		addrlen = sizeof (struct sockaddr_in);
2158 		break;
2159 	case AF_INET6:
2160 		sin6->sin6_port = 0;
2161 		sin6->sin6_addr = loopback_addr;
2162 		addrlen = sizeof (struct sockaddr_in6);
2163 		break;
2164 	}
2165 	ret = bind(s, (struct sockaddr *)&ss, addrlen);
2166 	if (ret != 0) {
2167 		rcm_log_message(RCM_ERROR,
2168 		    _("IP: mpathd bind: %s\n"), strerror(errno));
2169 		return (-1);
2170 	}
2171 	switch (family) {
2172 	case AF_INET:
2173 		sin->sin_port = htons(MPATHD_PORT);
2174 		break;
2175 	case AF_INET6:
2176 		sin6->sin6_port = htons(MPATHD_PORT);
2177 		break;
2178 	}
2179 	ret = connect(s, (struct sockaddr *)&ss, addrlen);
2180 	if (ret != 0) {
2181 		if (errno == ECONNREFUSED) {
2182 			/* in.mpathd is not running, start it */
2183 			if (rcm_exec_cmd(MPATHD_PATH) == -1) {
2184 				rcm_log_message(RCM_ERROR,
2185 				    _("IP: mpathd exec: %s\n"),
2186 				    strerror(errno));
2187 				return (-1);
2188 			}
2189 			ret = connect(s, (struct sockaddr *)&ss, addrlen);
2190 		}
2191 		if (ret != 0) {
2192 			rcm_log_message(RCM_ERROR,
2193 			    _("IP: mpathd connect: %s\n"), strerror(errno));
2194 			return (-1);
2195 		}
2196 	}
2197 	on = 0;
2198 	if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on,
2199 	    sizeof (on)) < 0) {
2200 		rcm_log_message(RCM_ERROR,
2201 		    _("IP: mpathd setsockopt TCP_ANONPRIVBIND: %s\n"),
2202 		    strerror(errno));
2203 		return (-1);
2204 	}
2205 
2206 	rcm_log_message(RCM_TRACE1, "IP: connect_to_mpathd success\n");
2207 
2208 	return (s);
2209 }
2210 
2211 /*
2212  * modop() - Remove/insert a module
2213  */
2214 static int
2215 modop(char *name, char *arg, int pos, char op)
2216 {
2217 	char syscmd[LIFNAMSIZ+MAXPATHLEN];	/* must be big enough */
2218 
2219 	rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name);
2220 
2221 	/* Nothing to do with "ip", "arp" */
2222 	if ((arg == NULL) || (strcmp(arg, "") == 0) ||
2223 	    STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) {
2224 		rcm_log_message(RCM_TRACE1, "IP: modop success\n");
2225 		return (0);
2226 	}
2227 
2228 	if (op == MOD_CHECK) {
2229 		/*
2230 		 * No known good modules (yet) apart from ip and arp
2231 		 * which are handled above
2232 		 */
2233 		return (-1);
2234 	}
2235 
2236 	if (op == MOD_REMOVE) {
2237 		(void) snprintf(syscmd, sizeof (syscmd),
2238 		    "%s %s modremove %s@%d\n", USR_SBIN_IFCONFIG, name, arg,
2239 		    pos);
2240 	} else if (op == MOD_INSERT) {
2241 		(void) snprintf(syscmd, sizeof (syscmd),
2242 		    "%s %s modinsert %s@%d\n", USR_SBIN_IFCONFIG, name, arg,
2243 		    pos);
2244 	} else {
2245 		rcm_log_message(RCM_ERROR,
2246 		    _("IP: modop(%s): unknown operation\n"), name);
2247 		return (-1);
2248 	}
2249 
2250 	rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd);
2251 	if (rcm_exec_cmd(syscmd) == -1) {
2252 		rcm_log_message(RCM_ERROR,
2253 		    _("IP: modop(%s): %s\n"), name, strerror(errno));
2254 		return (-1);
2255 	}
2256 
2257 	rcm_log_message(RCM_TRACE1, "IP: modop success\n");
2258 	return (0);
2259 }
2260 
2261 /*
2262  * get_modlist() - return a list of pushed mid-stream modules
2263  *		 Required memory is malloced to construct the list,
2264  *		 Caller must free this memory list
2265  *		 Call with cache_lock held
2266  */
2267 static int
2268 get_modlist(char *name, ip_lif_t *lif)
2269 {
2270 	int mux_fd;
2271 	int muxid_fd;
2272 	int fd;
2273 	int i;
2274 	int num_mods;
2275 	struct lifreq lifr;
2276 	struct str_list strlist;
2277 
2278 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name);
2279 
2280 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2281 	lifr.lifr_flags = lif->li_ifflags;
2282 	if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) {
2283 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name);
2284 		return (-1);
2285 	}
2286 
2287 	if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) {
2288 		rcm_log_message(RCM_ERROR,
2289 		    _("IP: get_modlist(%s): I_LIST(%s) \n"),
2290 		    name, strerror(errno));
2291 		(void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
2292 		return (-1);
2293 	}
2294 
2295 	strlist.sl_nmods = num_mods;
2296 	strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods);
2297 
2298 	if (strlist.sl_modlist == NULL) {
2299 		rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"),
2300 		    name, strerror(errno));
2301 		(void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
2302 		return (-1);
2303 	}
2304 
2305 	if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
2306 		rcm_log_message(RCM_ERROR,
2307 		    _("IP: get_modlist(%s): I_LIST error: %s\n"),
2308 		    name, strerror(errno));
2309 		(void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
2310 		return (-1);
2311 	}
2312 
2313 	for (i = 0; i < strlist.sl_nmods; i++) {
2314 		lif->li_modules[i] =
2315 		    malloc(strlen(strlist.sl_modlist[i].l_name)+1);
2316 		if (lif->li_modules[i] == NULL) {
2317 			rcm_log_message(RCM_ERROR,
2318 			    _("IP: get_modlist(%s): %s\n"),
2319 			    name, strerror(errno));
2320 			(void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
2321 			return (-1);
2322 		}
2323 		(void) strcpy(lif->li_modules[i], strlist.sl_modlist[i].l_name);
2324 	}
2325 
2326 	lif->li_modcnt = strlist.sl_nmods;
2327 	free(strlist.sl_modlist);
2328 
2329 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name);
2330 	return (ip_plink(mux_fd, muxid_fd, fd, &lifr));
2331 }
2332 
2333 /*
2334  * ip_domux2fd() - Helper function for mod*() functions
2335  *		 Stolen from ifconfig.c
2336  */
2337 static int
2338 ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr)
2339 {
2340 	int muxid_fd;
2341 	char	*udp_dev_name;
2342 
2343 	if (lifr->lifr_flags & IFF_IPV6) {
2344 		udp_dev_name  = UDP6_DEV_NAME;
2345 	} else {
2346 		udp_dev_name  = UDP_DEV_NAME;
2347 	}
2348 
2349 	if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) {
2350 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2351 		    udp_dev_name, strerror(errno));
2352 		return (-1);
2353 	}
2354 	if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) {
2355 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2356 		    udp_dev_name, strerror(errno));
2357 		(void) close(muxid_fd);
2358 		return (-1);
2359 	}
2360 	if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) {
2361 		rcm_log_message(RCM_ERROR,
2362 		    _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"),
2363 		    udp_dev_name, strerror(errno));
2364 		(void) close(*mux_fd);
2365 		(void) close(muxid_fd);
2366 		return (-1);
2367 	}
2368 
2369 	rcm_log_message(RCM_TRACE2,
2370 	    "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n",
2371 	    lifr->lifr_arp_muxid, lifr->lifr_ip_muxid);
2372 
2373 	if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) {
2374 		rcm_log_message(RCM_ERROR,
2375 		    _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"),
2376 		    udp_dev_name, strerror(errno));
2377 		(void) close(*mux_fd);
2378 		(void) close(muxid_fd);
2379 		return (-1);
2380 	}
2381 	if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) {
2382 		rcm_log_message(RCM_ERROR,
2383 		    _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"),
2384 		    udp_dev_name, strerror(errno));
2385 		(void) close(*mux_fd);
2386 		(void) close(muxid_fd);
2387 		return (-1);
2388 	}
2389 
2390 	/* Note: mux_fd and muxid_fd are closed in ip_plink below */
2391 	*muxid_fdp = muxid_fd;
2392 	return (0);
2393 }
2394 
2395 /*
2396  * ip_plink() - Helper function for mod*() functions.
2397  *	      Stolen from ifconfig.c
2398  */
2399 static int
2400 ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr)
2401 {
2402 	int mux_id;
2403 
2404 	if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) {
2405 		rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"),
2406 		    UDP_DEV_NAME, strerror(errno));
2407 		(void) close(mux_fd);
2408 		(void) close(muxid_fd);
2409 		(void) close(fd);
2410 		return (-1);
2411 	}
2412 
2413 	lifr->lifr_ip_muxid = mux_id;
2414 	if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) {
2415 		rcm_log_message(RCM_ERROR,
2416 		    _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"),
2417 		    UDP_DEV_NAME, strerror(errno));
2418 		(void) close(mux_fd);
2419 		(void) close(muxid_fd);
2420 		(void) close(fd);
2421 		return (-1);
2422 	}
2423 
2424 	(void) close(mux_fd);
2425 	(void) close(muxid_fd);
2426 	(void) close(fd);
2427 	return (0);
2428 }
2429 
2430 /*
2431  * ip_onlinelist()
2432  *
2433  *	Notify online to IP address consumers.
2434  */
2435 static int
2436 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2437 		rcm_info_t **depend_info)
2438 {
2439 	char **addrlist;
2440 	int ret = RCM_SUCCESS;
2441 
2442 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n");
2443 
2444 	addrlist = ip_get_addrlist(node);
2445 	if (addrlist == NULL || addrlist[0] == NULL) {
2446 		rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n");
2447 		ip_free_addrlist(addrlist);
2448 		return (ret);
2449 	}
2450 
2451 	ret = rcm_notify_online_list(hd, addrlist, 0, depend_info);
2452 
2453 	ip_free_addrlist(addrlist);
2454 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n");
2455 	return (ret);
2456 }
2457 
2458 /*
2459  * ip_offlinelist()
2460  *
2461  *	Offline IP address consumers.
2462  */
2463 static int
2464 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2465 	rcm_info_t **depend_info)
2466 {
2467 	char **addrlist;
2468 	int ret = RCM_SUCCESS;
2469 
2470 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n");
2471 
2472 	addrlist = ip_get_addrlist(node);
2473 	if (addrlist == NULL || addrlist[0] == NULL) {
2474 		rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n");
2475 		ip_free_addrlist(addrlist);
2476 		return (RCM_SUCCESS);
2477 	}
2478 
2479 	if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info))
2480 	    != RCM_SUCCESS) {
2481 		if (ret == RCM_FAILURE)
2482 			(void) rcm_notify_online_list(hd, addrlist, 0, NULL);
2483 
2484 		ret = RCM_FAILURE;
2485 	}
2486 
2487 	ip_free_addrlist(addrlist);
2488 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n");
2489 	return (ret);
2490 }
2491 
2492 /*
2493  * ip_get_addrlist() -	Compile list of IP addresses hosted on this NIC (node)
2494  *			This routine malloc() required memeory for the list
2495  *			Returns list on success, NULL if failed
2496  *			Call with cache_lock held.
2497  */
2498 static char **
2499 ip_get_addrlist(ip_cache_t *node)
2500 {
2501 	ip_lif_t *lif;
2502 	char **addrlist = NULL;
2503 	int numifs;
2504 	char addrstr[INET6_ADDRSTRLEN];
2505 	void *addr;
2506 	int af;
2507 	int i;
2508 
2509 	rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n",
2510 	    node->ip_resource);
2511 
2512 	numifs = 0;
2513 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
2514 		numifs++;
2515 	}
2516 
2517 	/*
2518 	 * Allocate space for resource names list; add 1 and use calloc()
2519 	 * so that the list is NULL-terminated.
2520 	 */
2521 	if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) {
2522 		rcm_log_message(RCM_ERROR,
2523 		    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2524 		    node->ip_resource, strerror(errno));
2525 		return (NULL);
2526 	}
2527 
2528 	for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL;
2529 	    lif = lif->li_next, i++) {
2530 
2531 		af = lif->li_addr.family;
2532 		if (af == AF_INET6) {
2533 			addr = &lif->li_addr.ip6.sin6_addr;
2534 		} else if (af == AF_INET) {
2535 			addr = &lif->li_addr.ip4.sin_addr;
2536 		} else {
2537 			rcm_log_message(RCM_DEBUG,
2538 			    "IP: unknown addr family %d, assuming AF_INET\n",
2539 			    af);
2540 			af = AF_INET;
2541 			addr = &lif->li_addr.ip4.sin_addr;
2542 		}
2543 		if (inet_ntop(af, addr, addrstr, INET6_ADDRSTRLEN) == NULL) {
2544 			rcm_log_message(RCM_ERROR,
2545 			    _("IP: inet_ntop: %s\n"), strerror(errno));
2546 			ip_free_addrlist(addrlist);
2547 			return (NULL);
2548 		}
2549 
2550 		if ((addrlist[i] = malloc(strlen(addrstr) + RCM_SIZE_SUNW_IP))
2551 		    == NULL) {
2552 			rcm_log_message(RCM_ERROR,
2553 			    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2554 			    node->ip_resource, strerror(errno));
2555 			ip_free_addrlist(addrlist);
2556 			return (NULL);
2557 		}
2558 		(void) strcpy(addrlist[i], RCM_STR_SUNW_IP);	/* SUNW_ip/ */
2559 		(void) strcat(addrlist[i], addrstr);	/* SUNW_ip/<address> */
2560 
2561 		rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]);
2562 	}
2563 
2564 	rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n",
2565 	    node->ip_resource);
2566 
2567 	return (addrlist);
2568 }
2569 
2570 static void
2571 ip_free_addrlist(char **addrlist)
2572 {
2573 	int i;
2574 
2575 	if (addrlist == NULL)
2576 		return;
2577 
2578 	for (i = 0; addrlist[i] != NULL; i++)
2579 		free(addrlist[i]);
2580 	free(addrlist);
2581 }
2582 
2583 /*
2584  * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
2585  */
2586 
2587 static void
2588 ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
2589     uint_t flags, rcm_info_t **depend_info)
2590 {
2591 	char cached_name[RCM_LINK_RESOURCE_MAX];
2592 	ip_cache_t *node;
2593 
2594 	assert(linkid != DATALINK_INVALID_LINKID);
2595 
2596 	rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid);
2597 
2598 	/* Check for the interface in the cache */
2599 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2600 	    RCM_LINK_PREFIX, linkid);
2601 
2602 	(void) mutex_lock(&cache_lock);
2603 	if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) {
2604 		rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"),
2605 		    linkid);
2606 		(void) mutex_unlock(&cache_lock);
2607 		return;
2608 	}
2609 	/*
2610 	 * Inform anonymous consumers about IP addresses being
2611 	 * onlined
2612 	 */
2613 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
2614 
2615 	(void) mutex_unlock(&cache_lock);
2616 
2617 	rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n");
2618 	return;
2619 
2620 }
2621 
2622 /*
2623  * if_configure() - Configure a physical interface after attach
2624  */
2625 static int
2626 if_configure(datalink_id_t linkid)
2627 {
2628 	char ifinst[MAXLINKNAMELEN];
2629 	char cfgfile[MAXPATHLEN];
2630 	char cached_name[RCM_LINK_RESOURCE_MAX];
2631 	struct stat statbuf;
2632 	ip_cache_t *node;
2633 	int af = 0;
2634 	int ipmp = 0;
2635 
2636 	assert(linkid != DATALINK_INVALID_LINKID);
2637 
2638 	rcm_log_message(RCM_TRACE1, _("IP: if_configure(%u)\n"), linkid);
2639 
2640 	/* Check for the interface in the cache */
2641 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2642 	    RCM_LINK_PREFIX, linkid);
2643 
2644 	/* Check if the interface is new or was previously offlined */
2645 	(void) mutex_lock(&cache_lock);
2646 	if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) &&
2647 	    (!(node->ip_cachestate & CACHE_IF_OFFLINED))) {
2648 		rcm_log_message(RCM_TRACE1,
2649 		    _("IP: Skipping configured interface(%u)\n"), linkid);
2650 		(void) mutex_unlock(&cache_lock);
2651 		return (0);
2652 	}
2653 	(void) mutex_unlock(&cache_lock);
2654 
2655 	if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, ifinst,
2656 	    sizeof (ifinst)) != DLADM_STATUS_OK) {
2657 		rcm_log_message(RCM_ERROR,
2658 		    _("IP: get %u link name failed\n"), linkid);
2659 		return (-1);
2660 	}
2661 
2662 	/* Scan IPv4 configuration first */
2663 	(void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4, ifinst);
2664 	cfgfile[MAXPATHLEN - 1] = '\0';
2665 
2666 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2667 	if (stat(cfgfile, &statbuf) == 0) {
2668 		af |= CONFIG_AF_INET;
2669 		if (isgrouped(cfgfile)) {
2670 			ipmp++;
2671 		}
2672 	}
2673 
2674 	/* Scan IPv6 configuration details */
2675 	(void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV6, ifinst);
2676 	cfgfile[MAXPATHLEN - 1] = '\0';
2677 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2678 	if (stat(cfgfile, &statbuf) == 0) {
2679 		af |= CONFIG_AF_INET6;
2680 		if ((ipmp == 0) && isgrouped(cfgfile)) {
2681 			ipmp++;
2682 		}
2683 	}
2684 
2685 	if (af & CONFIG_AF_INET) {
2686 		if (if_ipmp_config(ifinst, CONFIG_AF_INET, ipmp) == -1) {
2687 			rcm_log_message(RCM_ERROR,
2688 			    _("IP: IPv4 Post-attach failed (%s)\n"), ifinst);
2689 			return (-1);
2690 		}
2691 	}
2692 
2693 	if (af & CONFIG_AF_INET6) {
2694 		if (if_ipmp_config(ifinst, CONFIG_AF_INET6, ipmp) == -1) {
2695 			rcm_log_message(RCM_ERROR,
2696 			    _("IP: IPv6 Post-attach failed(%s)\n"), ifinst);
2697 			return (-1);
2698 		}
2699 	}
2700 
2701 	rcm_log_message(RCM_TRACE1, "IP: if_configure(%s) success\n", ifinst);
2702 
2703 	return (0);
2704 
2705 }
2706 
2707 /*
2708  * isgrouped() - Scans the given config file to see if this is a grouped
2709  *	       interface
2710  *	       Returns non-zero if true; 0 if false
2711  */
2712 static int
2713 isgrouped(char *cfgfile)
2714 {
2715 	FILE *fp;
2716 	struct stat statb;
2717 	char *buf = NULL;
2718 	char *tokens[MAXARGS];		/* token pointers */
2719 	char tspace[MAXLINE];		/* token space */
2720 	int ntok;
2721 	int group = 0;
2722 
2723 	if (cfgfile == NULL)
2724 		return (0);
2725 
2726 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile);
2727 
2728 	if (stat(cfgfile, &statb) != 0) {
2729 		rcm_log_message(RCM_TRACE1,
2730 		    _("IP: No config file(%s)\n"), cfgfile);
2731 		return (0);
2732 	}
2733 
2734 	/*
2735 	 * We also ignore single-byte config files because the file should
2736 	 * always be newline-terminated, so we know there's nothing of
2737 	 * interest.  Further, a single-byte file would cause the fgets() loop
2738 	 * below to spin forever.
2739 	 */
2740 	if (statb.st_size <= 1) {
2741 		rcm_log_message(RCM_TRACE1,
2742 		    _("IP: Empty config file(%s)\n"), cfgfile);
2743 		return (0);
2744 	}
2745 
2746 	if ((fp = fopen(cfgfile, "r")) == NULL) {
2747 		rcm_log_message(RCM_ERROR,
2748 		    _("IP: Cannot open configuration file(%s): %s\n"), cfgfile,
2749 		    strerror(errno));
2750 		return (0);
2751 	}
2752 
2753 	if ((buf = calloc(1, statb.st_size)) == NULL) {
2754 		rcm_log_message(RCM_ERROR,
2755 		    _("IP: calloc failure(%s): %s\n"), cfgfile,
2756 		    strerror(errno));
2757 		(void) fclose(fp);
2758 		return (0);
2759 	}
2760 
2761 	while (fgets(buf, statb.st_size, fp) != NULL) {
2762 		if (*buf == '\0')
2763 			continue;
2764 
2765 		tokenize(buf, tokens, tspace, &ntok);
2766 		while (ntok) {
2767 			if (STREQ("group", tokens[ntok - 1])) {
2768 				if (tokens[ntok] != NULL) {
2769 					group++;
2770 				}
2771 			}
2772 			ntok--;
2773 		}
2774 	}
2775 
2776 	free(buf);
2777 
2778 	(void) fclose(fp);
2779 
2780 	if (group <= 0) {
2781 		rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s) non-grouped\n",
2782 		    cfgfile);
2783 		return (0);
2784 	} else {
2785 		rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s) grouped\n",
2786 		    cfgfile);
2787 		return (1);
2788 	}
2789 }
2790 
2791 
2792 /*
2793  * if_ipmp_config() - Configure an interface instance as specified by the
2794  *		    address family af and if it is grouped (ipmp).
2795  */
2796 static int
2797 if_ipmp_config(char *ifinst, int af, int ipmp)
2798 {
2799 	char cfgfile[MAXPATHLEN];	/* configuration file */
2800 	FILE *fp;
2801 	struct stat statb;
2802 	char *buf;
2803 	char *tokens[MAXARGS];		/* list of config attributes */
2804 	char tspace[MAXLINE];		/* token space */
2805 	char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
2806 	char grpcmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
2807 	char fstr[8];		/* address family string inet or inet6 */
2808 	int nofailover = 0;
2809 	int newattach = 0;
2810 	int cmdvalid = 0;
2811 	int ntok;
2812 	int n;
2813 	int stdif = 0;
2814 
2815 	if (ifinst == NULL)
2816 		return (0);
2817 
2818 	rcm_log_message(RCM_TRACE1, "IP: if_ipmp_config(%s) ipmp = %d\n",
2819 	    ifinst, ipmp);
2820 
2821 	if (af & CONFIG_AF_INET) {
2822 		(void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4,
2823 		    ifinst);
2824 		(void) strcpy(fstr, "inet");
2825 	} else if (af & CONFIG_AF_INET6) {
2826 		(void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV6,
2827 		    ifinst);
2828 		(void) strcpy(fstr, "inet6");
2829 	} else {
2830 		return (0);		/* nothing to do */
2831 	}
2832 
2833 	cfgfile[MAXPATHLEN - 1] = '\0';
2834 	grpcmd[0] = '\0';
2835 
2836 	if (stat(cfgfile, &statb) != 0) {
2837 		rcm_log_message(RCM_TRACE1,
2838 		    "IP: No config file(%s)\n", ifinst);
2839 		return (0);
2840 	}
2841 
2842 	/* Config file exists, plumb in the physical interface */
2843 	if (af & CONFIG_AF_INET6) {
2844 		if (if_getcount(AF_INET6) == 0) {
2845 			/*
2846 			 * Configure software loopback driver if this is the
2847 			 * first IPv6 interface plumbed
2848 			 */
2849 			newattach++;
2850 			(void) snprintf(syscmd, sizeof (syscmd),
2851 			    "%s lo0 %s plumb ::1 up", USR_SBIN_IFCONFIG, fstr);
2852 			if (rcm_exec_cmd(syscmd) != 0) {
2853 				rcm_log_message(RCM_ERROR,
2854 				    _("IP: Cannot plumb (%s) %s\n"),
2855 				    ifinst, strerror(errno));
2856 				return (-1);
2857 			}
2858 		}
2859 		(void) snprintf(syscmd, sizeof (syscmd), "%s %s %s plumb up",
2860 		    USR_SBIN_IFCONFIG, ifinst, fstr);
2861 	} else {
2862 		(void) snprintf(syscmd, sizeof (syscmd), "%s %s %s plumb ",
2863 		    USR_SBIN_IFCONFIG, ifinst, fstr);
2864 		if (if_getcount(AF_INET) == 0) {
2865 			newattach++;
2866 		}
2867 	}
2868 	rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd);
2869 
2870 	if (rcm_exec_cmd(syscmd) != 0) {
2871 		rcm_log_message(RCM_ERROR,
2872 		    _("IP: Cannot plumb (%s) %s\n"), ifinst, strerror(errno));
2873 		return (-1);
2874 	}
2875 
2876 	/* Check if config file is empty, if so, nothing else to do */
2877 	if (statb.st_size == 0) {
2878 		rcm_log_message(RCM_TRACE1,
2879 		    "IP: Zero size config file(%s)\n", ifinst);
2880 		return (0);
2881 	}
2882 
2883 	if ((fp = fopen(cfgfile, "r")) == NULL) {
2884 		rcm_log_message(RCM_ERROR,
2885 		    _("IP: Open error(%s): %s\n"), cfgfile, strerror(errno));
2886 		return (-1);
2887 	}
2888 
2889 	if ((buf = calloc(1, statb.st_size)) == NULL) {
2890 		rcm_log_message(RCM_ERROR,
2891 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2892 		(void) fclose(fp);
2893 		return (-1);
2894 	}
2895 
2896 	/* a single line with one token implies a classical if */
2897 	if (fgets(buf, statb.st_size, fp) != NULL) {
2898 		tokenize(buf, tokens, tspace, &ntok);
2899 		if (ntok == 1) {
2900 			rcm_log_message(RCM_TRACE1, "IP: Standard interface\n");
2901 			stdif++;
2902 		}
2903 	}
2904 	if (fseek(fp, 0L, SEEK_SET) == -1) {
2905 		rcm_log_message(RCM_ERROR, _("IP: fseek: %s\n"),
2906 		    strerror(errno));
2907 		return (-1);
2908 	}
2909 
2910 	/*
2911 	 * Process the config command
2912 	 * This loop also handles multiple logical interfaces that may
2913 	 * be configured on a single line
2914 	 */
2915 	while (fgets(buf, statb.st_size, fp) != NULL) {
2916 		nofailover = 0;
2917 		cmdvalid = 0;
2918 
2919 		if (*buf == '\0')
2920 			continue;
2921 
2922 		tokenize(buf, tokens, tspace, &ntok);
2923 		if (ntok <= 0)
2924 			continue;
2925 
2926 		/* Reset the config command */
2927 		(void) snprintf(syscmd, sizeof (syscmd), "%s %s %s ",
2928 		    USR_SBIN_IFCONFIG, ifinst, fstr);
2929 
2930 		/* No parsing if this is first interface of its kind */
2931 		if (newattach) {
2932 			(void) strcat(syscmd, buf);
2933 			/* Classic if */
2934 			if ((af & CONFIG_AF_INET) && (stdif == 1)) {
2935 				(void) strcat(syscmd, CFG_CMDS_STD);
2936 			}
2937 			rcm_log_message(RCM_TRACE1, "IP: New: %s\n", syscmd);
2938 			if (rcm_exec_cmd(syscmd) != 0) {
2939 				rcm_log_message(RCM_ERROR,
2940 				    _("IP: Error: %s (%s): %s\n"),
2941 				    syscmd, ifinst, strerror(errno));
2942 			}
2943 			continue;
2944 		}
2945 
2946 		/* Parse the tokens to determine nature of the interface */
2947 		for (n = 0; n < ntok; n++) {
2948 			/* Handle pathological failover cases */
2949 			if (STREQ("-failover", tokens[n]))
2950 				nofailover++;
2951 			if (STREQ("failover", tokens[n]))
2952 				nofailover--;
2953 
2954 			/* group attribute requires special processing */
2955 			if (STREQ("group", tokens[n])) {
2956 				if (tokens[n + 1] != NULL) {
2957 					(void) snprintf(grpcmd, sizeof (grpcmd),
2958 					    "%s %s %s %s %s", USR_SBIN_IFCONFIG,
2959 					    ifinst, fstr,
2960 					    tokens[n], tokens[n + 1]);
2961 					n++;		/* skip next token */
2962 					continue;
2963 				}
2964 			}
2965 
2966 			/* Execute buffered command ? */
2967 			if (STREQ("set", tokens[n]) ||
2968 			    STREQ("addif", tokens[n]) ||
2969 			    STREQ("removeif", tokens[n]) ||
2970 			    (n == (ntok -1))) {
2971 
2972 				/* config command complete ? */
2973 				if (n == (ntok -1)) {
2974 					ADDSPACE(syscmd);
2975 					(void) strcat(syscmd, tokens[n]);
2976 					cmdvalid++;
2977 				}
2978 
2979 				if (!cmdvalid) {
2980 					ADDSPACE(syscmd);
2981 					(void) strcat(syscmd, tokens[n]);
2982 					cmdvalid++;
2983 					continue;
2984 				}
2985 				/* Classic if ? */
2986 				if ((af & CONFIG_AF_INET) && (stdif == 1)) {
2987 					(void) strcat(syscmd, CFG_CMDS_STD);
2988 				}
2989 
2990 				if (nofailover > 0) {
2991 					rcm_log_message(RCM_TRACE1,
2992 					    "IP: Interim exec: %s\n", syscmd);
2993 					if (rcm_exec_cmd(syscmd) != 0) {
2994 						rcm_log_message(RCM_ERROR,
2995 						    _("IP: %s fail(%s): %s\n"),
2996 						    syscmd, ifinst,
2997 						    strerror(errno));
2998 					}
2999 				} else {
3000 					/* Have mpathd configure the address */
3001 					if (if_mpathd_configure(syscmd, ifinst,
3002 					    af, ipmp) != 0) {
3003 						rcm_log_message(RCM_ERROR,
3004 						    _("IP: %s fail(%s): %s\n"),
3005 						    syscmd, ifinst,
3006 						    strerror(errno));
3007 					}
3008 				}
3009 
3010 				/* Reset config command */
3011 				(void) snprintf(syscmd, sizeof (syscmd),
3012 				    "%s %s %s ", USR_SBIN_IFCONFIG, ifinst,
3013 				    fstr);
3014 				nofailover = 0;
3015 				cmdvalid = 0;
3016 			}
3017 			/*
3018 			 * Note: No explicit command validation is required
3019 			 *	since ifconfig to does it for us
3020 			 */
3021 			ADDSPACE(syscmd);
3022 			(void) strcat(syscmd, tokens[n]);
3023 			cmdvalid++;
3024 		}
3025 	}
3026 
3027 	free(buf);
3028 	(void) fclose(fp);
3029 
3030 	/*
3031 	 * The group name needs to be set after all the test/nofailover
3032 	 * addresses have been configured. Otherwise, if IPMP detects that the
3033 	 * interface is failed, the addresses will be moved to a working
3034 	 * interface before the '-failover' flag can be set.
3035 	 */
3036 	if (grpcmd[0] != '\0') {
3037 		rcm_log_message(RCM_TRACE1, "IP: set group name: %s\n", grpcmd);
3038 		if (rcm_exec_cmd(grpcmd) != 0) {
3039 			rcm_log_message(RCM_ERROR, _("IP: %s fail(%s): %s\n"),
3040 			    grpcmd, ifinst, strerror(errno));
3041 		}
3042 	}
3043 
3044 	rcm_log_message(RCM_TRACE1, "IP: if_ipmp_config(%s) success\n", ifinst);
3045 
3046 	return (0);
3047 }
3048 
3049 /*
3050  * if_mpathd_configure() - Determine configuration disposition of the interface
3051  */
3052 static int
3053 if_mpathd_configure(char *syscmd, char *ifinst, int af, int ipmp)
3054 {
3055 	char *tokens[MAXARGS];
3056 	char tspace[MAXLINE];
3057 	int ntok;
3058 	char *addr;
3059 	char *from_lifname;
3060 	mpathd_cmd_t mpdcmd;
3061 	int n;
3062 
3063 	rcm_log_message(RCM_TRACE1, "IP: if_mpathd_configure(%s): %s\n",
3064 	    ifinst, syscmd);
3065 
3066 	tokenize(syscmd, tokens, tspace, &ntok);
3067 	if (ntok <= 0)
3068 		return (0);
3069 
3070 	addr = tokens[3];	/* by default, third token is valid address */
3071 	for (n = 0; n < ntok; n++) {
3072 		if (STREQ("set", tokens[n]) ||
3073 		    STREQ("addif", tokens[n])) {
3074 			addr = tokens[n+1];
3075 			if (addr == NULL) {	/* invalid format */
3076 				return (-1);
3077 			} else
3078 				break;
3079 		}
3080 	}
3081 
3082 	/* Check std. commands or no failed over address */
3083 	if (STREQ("removeif", addr) || STREQ("group", addr) ||
3084 	    ((from_lifname = get_mpathd_dest(addr, af)) == NULL)) {
3085 		rcm_log_message(RCM_TRACE1,
3086 		    "IP: No failed-over host, exec %s\n", syscmd);
3087 		if (rcm_exec_cmd(syscmd) != 0) {
3088 			rcm_log_message(RCM_ERROR,
3089 			    _("IP: %s failed(%s): %s\n"),
3090 			    syscmd, ifinst, strerror(errno));
3091 			return (-1);
3092 		}
3093 		return (0);
3094 	}
3095 
3096 	/* Check for non-IPMP failover scenarios */
3097 	if ((ipmp <= 0) && (from_lifname != NULL)) {
3098 		/* Address already hosted on another NIC, return */
3099 		rcm_log_message(RCM_TRACE1,
3100 		    "IP: Non-IPMP failed-over host(%s): %s\n",
3101 		    ifinst, addr);
3102 		return (0);
3103 	}
3104 
3105 	/*
3106 	 * Valid failed-over host; have mpathd set the original index
3107 	 */
3108 	mpdcmd.cmd_command = MI_SETOINDEX;
3109 	(void) strcpy(mpdcmd.from_lifname, from_lifname);
3110 	(void) strcpy(mpdcmd.to_pifname, ifinst);
3111 	if (af & CONFIG_AF_INET6) {
3112 		mpdcmd.addr_family = AF_INET6;
3113 	} else {
3114 		mpdcmd.addr_family = AF_INET;
3115 	}
3116 
3117 	/* Send command to in.mpathd(1M) */
3118 	rcm_log_message(RCM_TRACE1,
3119 	    "IP: Attempting setoindex from (%s) to (%s) ....\n",
3120 	    from_lifname, ifinst);
3121 
3122 	if (mpathd_send_cmd(&mpdcmd) < 0) {
3123 		rcm_log_message(RCM_TRACE1,
3124 		    "IP: mpathd set original index unsuccessful: %s\n",
3125 		    strerror(errno));
3126 		return (-1);
3127 	}
3128 
3129 	rcm_log_message(RCM_TRACE1,
3130 	    "IP: setoindex success (%s) to (%s)\n",
3131 	    from_lifname, ifinst);
3132 
3133 	return (0);
3134 }
3135 
3136 /*
3137  * get_mpathd_dest() - Return current destination for lif; caller is
3138  *		     responsible to free memory allocated for address
3139  */
3140 static char *
3141 get_mpathd_dest(char *addr, int family)
3142 {
3143 	int sock;
3144 	char *buf;
3145 	struct lifnum lifn;
3146 	struct lifconf lifc;
3147 	struct lifreq *lifrp;
3148 	sa_family_t af = AF_INET;	/* IPv4 by default */
3149 	int i;
3150 	struct lifreq lifreq;
3151 	struct sockaddr_in *sin;
3152 	struct sockaddr_in6 *sin6;
3153 	struct hostent *hp;
3154 	char *ifname = NULL;
3155 	char *prefix = NULL;
3156 	char addrstr[INET6_ADDRSTRLEN];
3157 	char ifaddr[INET6_ADDRSTRLEN];
3158 	int err;
3159 
3160 	if (addr == NULL) {
3161 		return (NULL);
3162 	}
3163 
3164 	rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s)\n", addr);
3165 
3166 	if (family & CONFIG_AF_INET6) {
3167 		af = AF_INET6;
3168 	} else {
3169 		af = AF_INET;
3170 	}
3171 
3172 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
3173 		rcm_log_message(RCM_ERROR,
3174 		    _("IP: failure opening %s socket: %s\n"),
3175 		    af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
3176 		return (NULL);
3177 	}
3178 
3179 	lifn.lifn_family = af;
3180 	lifn.lifn_flags = 0;
3181 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
3182 		rcm_log_message(RCM_ERROR,
3183 		    _("IP: SIOCLGIFNUM failed: %s\n"),
3184 		    strerror(errno));
3185 		(void) close(sock);
3186 		return (NULL);
3187 	}
3188 
3189 	if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) {
3190 		rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
3191 		    strerror(errno));
3192 		(void) close(sock);
3193 		return (NULL);
3194 	}
3195 
3196 	lifc.lifc_family = af;
3197 	lifc.lifc_flags = 0;
3198 	lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count;
3199 	lifc.lifc_buf = buf;
3200 
3201 	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
3202 		rcm_log_message(RCM_ERROR,
3203 		    _("IP: SIOCGLIFCONF failed: %s\n"),
3204 		    strerror(errno));
3205 		free(buf);
3206 		(void) close(sock);
3207 		return (NULL);
3208 	}
3209 
3210 	/* Filter out prefix address from netmask */
3211 	(void) strcpy(ifaddr, addr);
3212 	if ((prefix = strchr(ifaddr, '/')) != NULL) {
3213 		*prefix = '\0';	/* We care about the address part only */
3214 	}
3215 
3216 	/* Check for aliases */
3217 	hp = getipnodebyname(ifaddr, af, AI_DEFAULT, &err);
3218 	if (hp) {
3219 		if (inet_ntop(af, (void *)hp->h_addr_list[0],
3220 		    ifaddr, sizeof (ifaddr)) == NULL) {
3221 			/* Restore original address and use it */
3222 			(void) strcpy(ifaddr, addr);
3223 			if ((prefix = strchr(ifaddr, '/')) != NULL) {
3224 				*prefix = '\0';
3225 			}
3226 		}
3227 		freehostent(hp);
3228 	}
3229 	rcm_log_message(RCM_TRACE2, "IP: ifaddr(%s) = %s\n", addr, ifaddr);
3230 
3231 	/* now search the interfaces */
3232 	lifrp = lifc.lifc_req;
3233 	for (i = 0; i < lifn.lifn_count; i++, lifrp++) {
3234 		(void) strcpy(lifreq.lifr_name, lifrp->lifr_name);
3235 		/* Get the interface address for this interface */
3236 		if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) {
3237 			rcm_log_message(RCM_ERROR,
3238 			    _("IP: SIOCGLIFADDR: %s\n"), strerror(errno));
3239 			free(buf);
3240 			(void) close(sock);
3241 			return (NULL);
3242 		}
3243 
3244 		if (af == AF_INET6) {
3245 			sin6 = (struct sockaddr_in6 *)&lifreq.lifr_addr;
3246 			if (inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3247 			    addrstr, sizeof (addrstr)) == NULL) {
3248 				continue;
3249 			}
3250 		} else {
3251 			sin = (struct sockaddr_in *)&lifreq.lifr_addr;
3252 			if (inet_ntop(AF_INET, (void *)&sin->sin_addr,
3253 			    addrstr, sizeof (addrstr)) == NULL) {
3254 				continue;
3255 			}
3256 		}
3257 
3258 		if (STREQ(addrstr, ifaddr)) {
3259 			/* Allocate memory to hold interface name */
3260 			if ((ifname = (char *)malloc(LIFNAMSIZ)) == NULL) {
3261 				rcm_log_message(RCM_ERROR,
3262 				    _("IP: malloc: %s\n"), strerror(errno));
3263 				free(buf);
3264 				(void) close(sock);
3265 				return (NULL);
3266 			}
3267 
3268 			/* Copy the interface name */
3269 			/*
3270 			 * (void) memcpy(ifname, lifrp->lifr_name,
3271 			 *  sizeof (ifname));
3272 			 * ifname[sizeof (ifname) - 1] = '\0';
3273 			 */
3274 			(void) strcpy(ifname, lifrp->lifr_name);
3275 			break;
3276 		}
3277 	}
3278 
3279 	(void) close(sock);
3280 	free(buf);
3281 
3282 	if (ifname == NULL)
3283 		rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s): none\n",
3284 		    addr);
3285 	else
3286 		rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s): %s\n",
3287 		    addr, ifname);
3288 
3289 	return (ifname);
3290 }
3291 
3292 static int
3293 if_getcount(int af)
3294 {
3295 	int sock;
3296 	struct lifnum lifn;
3297 
3298 	rcm_log_message(RCM_TRACE1, "IP: if_getcount\n");
3299 
3300 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
3301 		rcm_log_message(RCM_ERROR,
3302 		    _("IP: failure opening %s socket: %s\n"),
3303 		    af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
3304 		return (-1);
3305 	}
3306 
3307 	lifn.lifn_family = af;
3308 	lifn.lifn_flags = 0;
3309 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
3310 		rcm_log_message(RCM_ERROR,
3311 		    _("IP: SIOCLGIFNUM failed: %s\n"),
3312 		    strerror(errno));
3313 		(void) close(sock);
3314 		return (-1);
3315 	}
3316 	(void) close(sock);
3317 
3318 	rcm_log_message(RCM_TRACE1, "IP: if_getcount success: %d\n",
3319 	    lifn.lifn_count);
3320 
3321 	return (lifn.lifn_count);
3322 }
3323 
3324 /*
3325  * tokenize() - turn a command line into tokens; caller is responsible to
3326  *	      provide enough memory to hold all tokens
3327  */
3328 static void
3329 tokenize(char *line, char **tokens, char *tspace, int *ntok)
3330 {
3331 	char *cp;
3332 	char *sp;
3333 
3334 	sp = tspace;
3335 	cp = line;
3336 	for (*ntok = 0; *ntok < MAXARGS; (*ntok)++) {
3337 		tokens[*ntok] = sp;
3338 		while (ISSPACE(*cp))
3339 			cp++;
3340 		if (ISEOL(*cp))
3341 			break;
3342 		do {
3343 			*sp++ = *cp++;
3344 		} while (!ISSPACE(*cp) && !ISEOL(*cp));
3345 
3346 		*sp++ = '\0';
3347 	}
3348 }
3349