17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5392b1d6eSyz  * Common Development and Distribution License (the "License").
6392b1d6eSyz  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2264639aafSDarren Reed  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
23a73be61aSHans Rosenfeld  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * This RCM module adds support to the RCM framework for IP managed
287c478bd9Sstevel@tonic-gate  * interfaces.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <assert.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <synch.h>
377c478bd9Sstevel@tonic-gate #include <libintl.h>
387c478bd9Sstevel@tonic-gate #include <errno.h>
397c478bd9Sstevel@tonic-gate #include <fcntl.h>
407c478bd9Sstevel@tonic-gate #include <sys/types.h>
41e11c3f44Smeem #include <sys/wait.h>
427c478bd9Sstevel@tonic-gate #include <sys/stat.h>
437c478bd9Sstevel@tonic-gate #include <sys/socket.h>
447c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
457c478bd9Sstevel@tonic-gate #include <net/if.h>
467c478bd9Sstevel@tonic-gate #include <netinet/in.h>
477c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
487c478bd9Sstevel@tonic-gate #include <stropts.h>
497c478bd9Sstevel@tonic-gate #include <strings.h>
50e11c3f44Smeem #include <sys/sysmacros.h>
51ff550d0eSmasputra #include <inet/ip.h>
52595aa6e4Smeem #include <libinetutil.h>
53d62bc4baSyz #include <libdllink.h>
54e11c3f44Smeem #include <libgen.h>
55e11c3f44Smeem #include <ipmp_admin.h>
566e91bba0SGirish Moodalbail #include <libipadm.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include "rcm_module.h"
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * Definitions
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate #ifndef lint
647c478bd9Sstevel@tonic-gate #define	_(x)	gettext(x)
657c478bd9Sstevel@tonic-gate #else
667c478bd9Sstevel@tonic-gate #define	_(x)	x
677c478bd9Sstevel@tonic-gate #endif
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /* Some generic well-knowns and defaults used in this module */
707c478bd9Sstevel@tonic-gate #define	ARP_MOD_NAME		"arp"		/* arp module */
717c478bd9Sstevel@tonic-gate #define	IP_MAX_MODS		9		/* max modules pushed on intr */
727c478bd9Sstevel@tonic-gate #define	MAX_RECONFIG_SIZE	1024		/* Max. reconfig string size */
737c478bd9Sstevel@tonic-gate 
74d62bc4baSyz #define	RCM_LINK_PREFIX		"SUNW_datalink"	/* RCM datalink name prefix */
75d62bc4baSyz #define	RCM_LINK_RESOURCE_MAX	(13 + LINKID_STR_WIDTH)
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #define	RCM_STR_SUNW_IP		"SUNW_ip/"	/* IP address export prefix */
787c478bd9Sstevel@tonic-gate 
79e11c3f44Smeem #define	SBIN_IFCONFIG		"/sbin/ifconfig" /* ifconfig command */
80e11c3f44Smeem #define	SBIN_IFPARSE		"/sbin/ifparse"	/* ifparse command */
81e11c3f44Smeem #define	DHCPFILE_FMT		"/etc/dhcp.%s"	/* DHCP config file */
82e11c3f44Smeem #define	CFGFILE_FMT_IPV4	"/etc/hostname.%s"  /* IPV4 config file */
83e11c3f44Smeem #define	CFGFILE_FMT_IPV6	"/etc/hostname6.%s" /* IPV6 config file */
847c478bd9Sstevel@tonic-gate #define	CFG_CMDS_STD	" netmask + broadcast + up" /* Normal config string */
85e11c3f44Smeem #define	CFG_DHCP_CMD		"dhcp wait 0"	/* command to start DHCP */
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /* Some useful macros */
887c478bd9Sstevel@tonic-gate #define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
897c478bd9Sstevel@tonic-gate #define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
907c478bd9Sstevel@tonic-gate #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /* Interface Cache state flags */
937c478bd9Sstevel@tonic-gate #define	CACHE_IF_STALE		0x1		/* stale cached data */
947c478bd9Sstevel@tonic-gate #define	CACHE_IF_NEW		0x2		/* new cached interface */
957c478bd9Sstevel@tonic-gate #define	CACHE_IF_OFFLINED	0x4		/* interface offlined */
96392b1d6eSyz #define	CACHE_IF_IGNORE		0x8		/* state held elsewhere */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /* Network Cache lookup options */
997c478bd9Sstevel@tonic-gate #define	CACHE_NO_REFRESH	0x1		/* cache refresh not needed */
1007c478bd9Sstevel@tonic-gate #define	CACHE_REFRESH		0x2		/* refresh cache */
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /* RCM IPMP Module specific property definitions */
1037c478bd9Sstevel@tonic-gate #define	RCM_IPMP_MIN_REDUNDANCY	1		/* default min. redundancy */
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /* Stream module operations */
1067c478bd9Sstevel@tonic-gate #define	MOD_INSERT		0	/* Insert a mid-stream module */
1077c478bd9Sstevel@tonic-gate #define	MOD_REMOVE		1	/* Remove a mid-stream module */
1087c478bd9Sstevel@tonic-gate #define	MOD_CHECK		2	/* Check mid-stream module safety */
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * IP module data types
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /* Physical interface representation */
1157c478bd9Sstevel@tonic-gate typedef struct ip_pif {
116e11c3f44Smeem 	char		pi_ifname[LIFNAMSIZ];	/* interface name */
117e11c3f44Smeem 	char		pi_grname[LIFGRNAMSIZ]; /* IPMP group name */
118e11c3f44Smeem 	struct ip_lif	*pi_lifs;		/* ptr to logical interfaces */
1197c478bd9Sstevel@tonic-gate } ip_pif_t;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /* Logical interface representation */
1227c478bd9Sstevel@tonic-gate typedef struct ip_lif
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	struct ip_lif		*li_next;	/* ptr to next lif */
12546fbc806SToomas Soome 	struct ip_lif		*li_prev;	/* previous next ptr */
1267c478bd9Sstevel@tonic-gate 	ip_pif_t		*li_pif;	/* back ptr to phy int */
1277c478bd9Sstevel@tonic-gate 	ushort_t		li_ifnum;	/* interface number */
1287c478bd9Sstevel@tonic-gate 	union {
1297c478bd9Sstevel@tonic-gate 		sa_family_t		family;
1307c478bd9Sstevel@tonic-gate 		struct sockaddr_storage storage;
1317c478bd9Sstevel@tonic-gate 		struct sockaddr_in	ip4;    /* IPv4 */
1327c478bd9Sstevel@tonic-gate 		struct sockaddr_in6	ip6;    /* IPv6 */
1337c478bd9Sstevel@tonic-gate 	} li_addr;
1347c478bd9Sstevel@tonic-gate 	uint64_t		li_ifflags;	/* current IFF_* flags */
1357c478bd9Sstevel@tonic-gate 	int			li_modcnt;	/* # of modules */
1367c478bd9Sstevel@tonic-gate 	char	*li_modules[IP_MAX_MODS];	/* module list pushed */
1377c478bd9Sstevel@tonic-gate 	char	*li_reconfig;			/* Reconfiguration string */
1387c478bd9Sstevel@tonic-gate 	int32_t			li_cachestate;	/* cache state flags */
1397c478bd9Sstevel@tonic-gate } ip_lif_t;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /* Cache element */
1427c478bd9Sstevel@tonic-gate typedef struct ip_cache
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	struct ip_cache		*ip_next;	/* next cached resource */
1457c478bd9Sstevel@tonic-gate 	struct ip_cache		*ip_prev;	/* prev cached resource */
1467c478bd9Sstevel@tonic-gate 	char			*ip_resource;	/* resource name */
1477c478bd9Sstevel@tonic-gate 	ip_pif_t		*ip_pif;	/* ptr to phy int */
1487c478bd9Sstevel@tonic-gate 	int32_t			ip_ifred;	/* min. redundancy */
1497c478bd9Sstevel@tonic-gate 	int			ip_cachestate;	/* cache state flags */
1507c478bd9Sstevel@tonic-gate } ip_cache_t;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /*
1537c478bd9Sstevel@tonic-gate  * Global cache for network interfaces
1547c478bd9Sstevel@tonic-gate  */
1557c478bd9Sstevel@tonic-gate static ip_cache_t	cache_head;
1567c478bd9Sstevel@tonic-gate static ip_cache_t	cache_tail;
1577c478bd9Sstevel@tonic-gate static mutex_t		cache_lock;
1587c478bd9Sstevel@tonic-gate static int		events_registered = 0;
1597c478bd9Sstevel@tonic-gate 
1604ac67f02SAnurag S. Maskey static dladm_handle_t	dld_handle = NULL;
1616e91bba0SGirish Moodalbail static ipadm_handle_t	ip_handle = NULL;
1624ac67f02SAnurag S. Maskey 
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate  * RCM module interface prototypes
1657c478bd9Sstevel@tonic-gate  */
1667c478bd9Sstevel@tonic-gate static int ip_register(rcm_handle_t *);
1677c478bd9Sstevel@tonic-gate static int ip_unregister(rcm_handle_t *);
1687c478bd9Sstevel@tonic-gate static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t,
1697c478bd9Sstevel@tonic-gate 			char **, char **, nvlist_t *, rcm_info_t **);
1707c478bd9Sstevel@tonic-gate static int ip_suspend(rcm_handle_t *, char *, id_t,
1717c478bd9Sstevel@tonic-gate 			timespec_t *, uint_t, char **, rcm_info_t **);
1727c478bd9Sstevel@tonic-gate static int ip_resume(rcm_handle_t *, char *, id_t, uint_t,
1737c478bd9Sstevel@tonic-gate 			char **, rcm_info_t **);
1747c478bd9Sstevel@tonic-gate static int ip_offline(rcm_handle_t *, char *, id_t, uint_t,
1757c478bd9Sstevel@tonic-gate 			char **, rcm_info_t **);
1767c478bd9Sstevel@tonic-gate static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
1777c478bd9Sstevel@tonic-gate 			char **, rcm_info_t **);
1787c478bd9Sstevel@tonic-gate static int ip_remove(rcm_handle_t *, char *, id_t, uint_t,
1797c478bd9Sstevel@tonic-gate 			char **, rcm_info_t **);
1807c478bd9Sstevel@tonic-gate static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t,
1817c478bd9Sstevel@tonic-gate 			char **, nvlist_t *, rcm_info_t **);
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /* Module private routines */
18446fbc806SToomas Soome static void	free_cache();
18546fbc806SToomas Soome static int	update_cache(rcm_handle_t *);
18646fbc806SToomas Soome static void	cache_remove(ip_cache_t *);
1877c478bd9Sstevel@tonic-gate static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char);
18846fbc806SToomas Soome static void	free_node(ip_cache_t *);
18946fbc806SToomas Soome static void	cache_insert(ip_cache_t *);
19046fbc806SToomas Soome static char	*ip_usage(ip_cache_t *);
19146fbc806SToomas Soome static int	update_pif(rcm_handle_t *, int, int, struct ifaddrs *);
19246fbc806SToomas Soome static int	ip_ipmp_offline(ip_cache_t *);
1937c478bd9Sstevel@tonic-gate static int	ip_ipmp_undo_offline(ip_cache_t *);
1947c478bd9Sstevel@tonic-gate static int	if_cfginfo(ip_cache_t *, uint_t);
1957c478bd9Sstevel@tonic-gate static int	if_unplumb(ip_cache_t *);
1967c478bd9Sstevel@tonic-gate static int	if_replumb(ip_cache_t *);
19746fbc806SToomas Soome static void	ip_log_err(ip_cache_t *, char **, char *);
198d62bc4baSyz static char	*get_link_resource(const char *);
1997c478bd9Sstevel@tonic-gate static void	clr_cfg_state(ip_pif_t *);
2007c478bd9Sstevel@tonic-gate static int	modop(char *, char *, int, char);
2017c478bd9Sstevel@tonic-gate static int	get_modlist(char *, ip_lif_t *);
202fc80c0dfSnordmark static int	ip_domux2fd(int *, int *, int *, struct lifreq *);
203fc80c0dfSnordmark static int	ip_plink(int, int, int, struct lifreq *);
2047c478bd9Sstevel@tonic-gate static int	ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
2057c478bd9Sstevel@tonic-gate 			rcm_info_t **);
2067c478bd9Sstevel@tonic-gate static int	ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
2077c478bd9Sstevel@tonic-gate 			rcm_info_t **);
20846fbc806SToomas Soome static char	**ip_get_addrlist(ip_cache_t *);
2097c478bd9Sstevel@tonic-gate static void	ip_free_addrlist(char **);
210d62bc4baSyz static void	ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **,
211d62bc4baSyz 			uint_t, rcm_info_t **);
212e11c3f44Smeem static boolean_t ip_addrstr(ip_lif_t *, char *, size_t);
2137c478bd9Sstevel@tonic-gate 
2146e91bba0SGirish Moodalbail static int if_configure_hostname(datalink_id_t);
2156e91bba0SGirish Moodalbail static int if_configure_ipadm(datalink_id_t);
2166e91bba0SGirish Moodalbail static boolean_t if_hostname_exists(char *, sa_family_t);
217e11c3f44Smeem static boolean_t isgrouped(const char *);
218e11c3f44Smeem static int if_config_inst(const char *, FILE *, int, boolean_t);
219e11c3f44Smeem static uint_t ntok(const char *cp);
220e11c3f44Smeem static boolean_t ifconfig(const char *, const char *, const char *, boolean_t);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate /* Module-Private data */
2237c478bd9Sstevel@tonic-gate static struct rcm_mod_ops ip_ops =
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	RCM_MOD_OPS_VERSION,
2267c478bd9Sstevel@tonic-gate 	ip_register,
2277c478bd9Sstevel@tonic-gate 	ip_unregister,
2287c478bd9Sstevel@tonic-gate 	ip_get_info,
2297c478bd9Sstevel@tonic-gate 	ip_suspend,
2307c478bd9Sstevel@tonic-gate 	ip_resume,
2317c478bd9Sstevel@tonic-gate 	ip_offline,
2327c478bd9Sstevel@tonic-gate 	ip_undo_offline,
2337c478bd9Sstevel@tonic-gate 	ip_remove,
2347c478bd9Sstevel@tonic-gate 	NULL,
2357c478bd9Sstevel@tonic-gate 	NULL,
2367c478bd9Sstevel@tonic-gate 	ip_notify_event
2377c478bd9Sstevel@tonic-gate };
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate /*
2407c478bd9Sstevel@tonic-gate  * rcm_mod_init() - Update registrations, and return the ops structure.
2417c478bd9Sstevel@tonic-gate  */
2427c478bd9Sstevel@tonic-gate struct rcm_mod_ops *
rcm_mod_init(void)2437c478bd9Sstevel@tonic-gate rcm_mod_init(void)
2447c478bd9Sstevel@tonic-gate {
245d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	char errmsg[DLADM_STRSIZE];
246d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	dladm_status_t status;
2476e91bba0SGirish Moodalbail 	ipadm_status_t iph_status;
248d4d1f7bfSVasumathi Sundaram - Sun Microsystems 
2497c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: mod_init\n");
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	cache_head.ip_next = &cache_tail;
2527c478bd9Sstevel@tonic-gate 	cache_head.ip_prev = NULL;
2537c478bd9Sstevel@tonic-gate 	cache_tail.ip_prev = &cache_head;
2547c478bd9Sstevel@tonic-gate 	cache_tail.ip_next = NULL;
25546fbc806SToomas Soome 	(void) mutex_init(&cache_lock, USYNC_THREAD, NULL);
2567c478bd9Sstevel@tonic-gate 
257d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
258d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		rcm_log_message(RCM_WARNING,
259d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		    "IP: mod_init failed: cannot get datalink handle: %s\n",
260d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		    dladm_status2str(status, errmsg));
261d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		return (NULL);
262d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	}
2634ac67f02SAnurag S. Maskey 
2646e91bba0SGirish Moodalbail 	if ((iph_status = ipadm_open(&ip_handle, 0)) != IPADM_SUCCESS) {
2656e91bba0SGirish Moodalbail 		rcm_log_message(RCM_ERROR,
2666e91bba0SGirish Moodalbail 		    "IP: mod_init failed: cannot get IP handle: %s\n",
2676e91bba0SGirish Moodalbail 		    ipadm_status2str(iph_status));
2686e91bba0SGirish Moodalbail 		dladm_close(dld_handle);
2696e91bba0SGirish Moodalbail 		dld_handle = NULL;
2706e91bba0SGirish Moodalbail 		return (NULL);
2716e91bba0SGirish Moodalbail 	}
2726e91bba0SGirish Moodalbail 
2737c478bd9Sstevel@tonic-gate 	/* Return the ops vectors */
2747c478bd9Sstevel@tonic-gate 	return (&ip_ops);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate /*
2787c478bd9Sstevel@tonic-gate  * rcm_mod_info() - Return a string describing this module.
2797c478bd9Sstevel@tonic-gate  */
2807c478bd9Sstevel@tonic-gate const char *
rcm_mod_info(void)2817c478bd9Sstevel@tonic-gate rcm_mod_info(void)
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: mod_info\n");
2847c478bd9Sstevel@tonic-gate 
285648495d6Svikram 	return ("IP Multipathing module version 1.23");
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate  * rcm_mod_fini() - Destroy the network interfaces cache.
2907c478bd9Sstevel@tonic-gate  */
2917c478bd9Sstevel@tonic-gate int
rcm_mod_fini(void)2927c478bd9Sstevel@tonic-gate rcm_mod_fini(void)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: mod_fini\n");
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	free_cache();
2977c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&cache_lock);
2984ac67f02SAnurag S. Maskey 
2994ac67f02SAnurag S. Maskey 	dladm_close(dld_handle);
3006e91bba0SGirish Moodalbail 	ipadm_close(ip_handle);
3017c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate  * ip_register() - Make sure the cache is properly sync'ed, and its
3067c478bd9Sstevel@tonic-gate  *		 registrations are in order.
3077c478bd9Sstevel@tonic-gate  */
3087c478bd9Sstevel@tonic-gate static int
ip_register(rcm_handle_t * hd)3097c478bd9Sstevel@tonic-gate ip_register(rcm_handle_t *hd)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: register\n");
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
3147c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	if (update_cache(hd) < 0)
3177c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/*
3207c478bd9Sstevel@tonic-gate 	 * Need to register interest in all new resources
3217c478bd9Sstevel@tonic-gate 	 * getting attached, so we get attach event notifications
3227c478bd9Sstevel@tonic-gate 	 */
3237c478bd9Sstevel@tonic-gate 	if (!events_registered) {
324d62bc4baSyz 		if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
3257c478bd9Sstevel@tonic-gate 		    != RCM_SUCCESS) {
3267c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
3277c478bd9Sstevel@tonic-gate 			    _("IP: failed to register %s\n"),
328d62bc4baSyz 			    RCM_RESOURCE_LINK_NEW);
3297c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
3307c478bd9Sstevel@tonic-gate 		} else {
3317c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
332d62bc4baSyz 			    RCM_RESOURCE_LINK_NEW);
3337c478bd9Sstevel@tonic-gate 			events_registered++;
3347c478bd9Sstevel@tonic-gate 		}
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate /*
3417c478bd9Sstevel@tonic-gate  * ip_unregister() - Walk the cache, unregistering all the networks.
3427c478bd9Sstevel@tonic-gate  */
3437c478bd9Sstevel@tonic-gate static int
ip_unregister(rcm_handle_t * hd)3447c478bd9Sstevel@tonic-gate ip_unregister(rcm_handle_t *hd)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate 	ip_cache_t *probe;
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: unregister\n");
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
3517c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	/* Walk the cache, unregistering everything */
3547c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
3557c478bd9Sstevel@tonic-gate 	probe = cache_head.ip_next;
3567c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
3577c478bd9Sstevel@tonic-gate 		if (rcm_unregister_interest(hd, probe->ip_resource, 0)
3587c478bd9Sstevel@tonic-gate 		    != RCM_SUCCESS) {
3597c478bd9Sstevel@tonic-gate 			/* unregister failed for whatever reason */
3607c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
3617c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
3627c478bd9Sstevel@tonic-gate 		}
3637c478bd9Sstevel@tonic-gate 		cache_remove(probe);
3647c478bd9Sstevel@tonic-gate 		free_node(probe);
3657c478bd9Sstevel@tonic-gate 		probe = cache_head.ip_next;
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	/*
3707c478bd9Sstevel@tonic-gate 	 * Need to unregister interest in all new resources
3717c478bd9Sstevel@tonic-gate 	 */
3727c478bd9Sstevel@tonic-gate 	if (events_registered) {
373d62bc4baSyz 		if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
3747c478bd9Sstevel@tonic-gate 		    != RCM_SUCCESS) {
3757c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
3767c478bd9Sstevel@tonic-gate 			    _("IP: failed to unregister %s\n"),
377d62bc4baSyz 			    RCM_RESOURCE_LINK_NEW);
3787c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
3797c478bd9Sstevel@tonic-gate 		} else {
3807c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
381d62bc4baSyz 			    RCM_RESOURCE_LINK_NEW);
3827c478bd9Sstevel@tonic-gate 			events_registered--;
3837c478bd9Sstevel@tonic-gate 		}
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate  * ip_offline() - Offline an interface.
3917c478bd9Sstevel@tonic-gate  */
3927c478bd9Sstevel@tonic-gate static int
ip_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)3937c478bd9Sstevel@tonic-gate ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
3947c478bd9Sstevel@tonic-gate     char **errorp, rcm_info_t **depend_info)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
3977c478bd9Sstevel@tonic-gate 	ip_pif_t *pif;
398e11c3f44Smeem 	boolean_t detachable = B_FALSE;
399e11c3f44Smeem 	boolean_t ipmp;
400e11c3f44Smeem 	int retval;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc);
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
4057c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
4067c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
4077c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
4087c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
4097c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/* Lock the cache and lookup the resource */
4127c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
4137c478bd9Sstevel@tonic-gate 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
4147c478bd9Sstevel@tonic-gate 	if (node == NULL) {
4157c478bd9Sstevel@tonic-gate 		ip_log_err(node, errorp, "Unrecognized resource");
4167c478bd9Sstevel@tonic-gate 		errno = ENOENT;
4177c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
4187c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	pif = node->ip_pif;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	/* Establish default detachability criteria */
424e11c3f44Smeem 	if (flags & RCM_FORCE)
425e11c3f44Smeem 		detachable = B_TRUE;
4267c478bd9Sstevel@tonic-gate 
427e11c3f44Smeem 	/* Check if the interface is under IPMP */
428e11c3f44Smeem 	ipmp = (pif->pi_grname[0] != '\0');
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	/*
431e11c3f44Smeem 	 * Even if the interface is not under IPMP, it's possible that it's
432e11c3f44Smeem 	 * still okay to offline it as long as there are higher-level failover
433e11c3f44Smeem 	 * mechanisms for the addresses it owns (e.g., clustering).  In this
434e11c3f44Smeem 	 * case, ip_offlinelist() will return RCM_SUCCESS, and we charge on.
4357c478bd9Sstevel@tonic-gate 	 */
4367c478bd9Sstevel@tonic-gate 	if (!ipmp && !detachable) {
4377c478bd9Sstevel@tonic-gate 		/* Inform consumers of IP addresses being offlined */
4387c478bd9Sstevel@tonic-gate 		if (ip_offlinelist(hd, node, errorp, flags, depend_info) ==
4397c478bd9Sstevel@tonic-gate 		    RCM_SUCCESS) {
4407c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
441392b1d6eSyz 			    "IP: consumers agree on detach");
4427c478bd9Sstevel@tonic-gate 		} else {
4437c478bd9Sstevel@tonic-gate 			ip_log_err(node, errorp,
444392b1d6eSyz 			    "Device consumers prohibit offline");
4457c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
4467c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
4477c478bd9Sstevel@tonic-gate 		}
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/* Check if it's a query */
4517c478bd9Sstevel@tonic-gate 	if (flags & RCM_QUERY) {
4527c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n",
4537c478bd9Sstevel@tonic-gate 		    rsrc);
4547c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
4557c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	/* Check detachability, save configuration if detachable */
4597c478bd9Sstevel@tonic-gate 	if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) {
4607c478bd9Sstevel@tonic-gate 		node->ip_cachestate |= CACHE_IF_IGNORE;
4617c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc);
4627c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
4637c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	/* standalone detachable device */
4677c478bd9Sstevel@tonic-gate 	if (!ipmp) {
4687c478bd9Sstevel@tonic-gate 		if (if_unplumb(node) < 0) {
4697c478bd9Sstevel@tonic-gate 			ip_log_err(node, errorp,
4707c478bd9Sstevel@tonic-gate 			    "Failed to unplumb the device");
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 			errno = EIO;
4737c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
4747c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
4757c478bd9Sstevel@tonic-gate 		}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 		node->ip_cachestate |= CACHE_IF_OFFLINED;
4787c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc);
4797c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
4807c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	/*
484e11c3f44Smeem 	 * This is an IPMP interface that can be offlined.
485bbf21555SRichard Lowe 	 * Request in.mpathd(8) to offline the physical interface.
4867c478bd9Sstevel@tonic-gate 	 */
487e11c3f44Smeem 	if ((retval = ip_ipmp_offline(node)) != IPMP_SUCCESS)
488e11c3f44Smeem 		ip_log_err(node, errorp, "in.mpathd offline failed");
4897c478bd9Sstevel@tonic-gate 
490e11c3f44Smeem 	if (retval == IPMP_EMINRED && !detachable) {
4917c478bd9Sstevel@tonic-gate 		/*
492bbf21555SRichard Lowe 		 * in.mpathd(8) could not offline the device because it was
493e11c3f44Smeem 		 * the last interface in the group.  However, it's possible
494e11c3f44Smeem 		 * that it's still okay to offline it as long as there are
495e11c3f44Smeem 		 * higher-level failover mechanisms for the addresses it owns
496e11c3f44Smeem 		 * (e.g., clustering).  In this case, ip_offlinelist() will
497e11c3f44Smeem 		 * return RCM_SUCCESS, and we charge on.
4987c478bd9Sstevel@tonic-gate 		 */
499e11c3f44Smeem 		/* Inform consumers of IP addresses being offlined */
500e11c3f44Smeem 		if (ip_offlinelist(hd, node, errorp, flags,
501e11c3f44Smeem 		    depend_info) == RCM_SUCCESS) {
502e11c3f44Smeem 			rcm_log_message(RCM_DEBUG,
503e11c3f44Smeem 			    "IP: consumers agree on detach");
504e11c3f44Smeem 		} else {
505e11c3f44Smeem 			ip_log_err(node, errorp,
506e11c3f44Smeem 			    "Device consumers prohibit offline");
507e11c3f44Smeem 			(void) mutex_unlock(&cache_lock);
508e11c3f44Smeem 			errno = EBUSY;
509e11c3f44Smeem 			return (RCM_FAILURE);
5107c478bd9Sstevel@tonic-gate 		}
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (if_unplumb(node) < 0) {
5147c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
5157c478bd9Sstevel@tonic-gate 		    _("IP: Unplumb failed (%s)\n"),
5167c478bd9Sstevel@tonic-gate 		    pif->pi_ifname);
5177c478bd9Sstevel@tonic-gate 
518e11c3f44Smeem 		/* Request in.mpathd to undo the offline */
519e11c3f44Smeem 		if (ip_ipmp_undo_offline(node) != IPMP_SUCCESS) {
5207c478bd9Sstevel@tonic-gate 			ip_log_err(node, errorp, "Undo offline failed");
5217c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
5227c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
5237c478bd9Sstevel@tonic-gate 		}
5247c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
5257c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	node->ip_cachestate |= CACHE_IF_OFFLINED;
5297c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc);
5307c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
5317c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate /*
5357c478bd9Sstevel@tonic-gate  * ip_undo_offline() - Undo offline of a previously offlined device.
5367c478bd9Sstevel@tonic-gate  */
5377c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5387c478bd9Sstevel@tonic-gate static int
ip_undo_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)5397c478bd9Sstevel@tonic-gate ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
5407c478bd9Sstevel@tonic-gate     char **errorp, rcm_info_t **depend_info)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
5477c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
5487c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
5497c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
5507c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
5517c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
5547c478bd9Sstevel@tonic-gate 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	if (node == NULL) {
5577c478bd9Sstevel@tonic-gate 		ip_log_err(node, errorp, "No such device");
5587c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
5597c478bd9Sstevel@tonic-gate 		errno = ENOENT;
5607c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	/* Check if no attempt should be made to online the device here */
5647c478bd9Sstevel@tonic-gate 	if (node->ip_cachestate & CACHE_IF_IGNORE) {
5657c478bd9Sstevel@tonic-gate 		node->ip_cachestate &= ~(CACHE_IF_IGNORE);
5667c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
5677c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	/* Check if the interface was previously offlined */
5717c478bd9Sstevel@tonic-gate 	if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) {
5727c478bd9Sstevel@tonic-gate 		ip_log_err(node, errorp, "Device not offlined");
5737c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
5747c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
5757c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	if (if_replumb(node) == -1) {
5797c478bd9Sstevel@tonic-gate 		/* re-plumb failed */
5807c478bd9Sstevel@tonic-gate 		ip_log_err(node, errorp, "Replumb failed");
5817c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
5827c478bd9Sstevel@tonic-gate 		errno = EIO;
5837c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	/* Inform consumers about IP addresses being un-offlined */
5887c478bd9Sstevel@tonic-gate 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	node->ip_cachestate &= ~(CACHE_IF_OFFLINED);
5917c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc);
5927c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
5937c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate  * ip_get_info() - Gather usage information for this resource.
5987c478bd9Sstevel@tonic-gate  */
5997c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6007c478bd9Sstevel@tonic-gate int
ip_get_info(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** usagep,char ** errorp,nvlist_t * props,rcm_info_t ** depend_info)6017c478bd9Sstevel@tonic-gate ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
6027c478bd9Sstevel@tonic-gate     char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info)
6037c478bd9Sstevel@tonic-gate {
6047c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
6057c478bd9Sstevel@tonic-gate 	char *infostr;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
6087c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
6097c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
6107c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
6117c478bd9Sstevel@tonic-gate 	assert(usagep != NULL);
6127c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
6137c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc);
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
6187c478bd9Sstevel@tonic-gate 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
6197c478bd9Sstevel@tonic-gate 	if (!node) {
6207c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_INFO,
6217c478bd9Sstevel@tonic-gate 		    _("IP: get_info(%s) unrecognized resource\n"), rsrc);
6227c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
6237c478bd9Sstevel@tonic-gate 		errno = ENOENT;
6247c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	infostr = ip_usage(node);
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	if (infostr == NULL) {
6307c478bd9Sstevel@tonic-gate 		/* most likely malloc failure */
6317c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
6327c478bd9Sstevel@tonic-gate 		    _("IP: get_info(%s) malloc failure\n"), rsrc);
6337c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
6347c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
6357c478bd9Sstevel@tonic-gate 		*errorp = NULL;
6367c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	/* Set client/role properties */
6407c478bd9Sstevel@tonic-gate 	(void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP");
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	/* Set usage property, infostr will be freed by caller */
6437c478bd9Sstevel@tonic-gate 	*usagep = infostr;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n",
6467c478bd9Sstevel@tonic-gate 	    rsrc, infostr);
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
6497c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
6507c478bd9Sstevel@tonic-gate }
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate /*
6537c478bd9Sstevel@tonic-gate  * ip_suspend() - Nothing to do, always okay
6547c478bd9Sstevel@tonic-gate  */
6557c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6567c478bd9Sstevel@tonic-gate static int
ip_suspend(rcm_handle_t * hd,char * rsrc,id_t id,timespec_t * interval,uint_t flags,char ** errorp,rcm_info_t ** depend_info)6577c478bd9Sstevel@tonic-gate ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
65846fbc806SToomas Soome     uint_t flags, char **errorp, rcm_info_t **depend_info)
6597c478bd9Sstevel@tonic-gate {
6607c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
6617c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
6627c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
6637c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
6647c478bd9Sstevel@tonic-gate 	assert(interval != NULL);
6657c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
6667c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc);
6697c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate /*
6737c478bd9Sstevel@tonic-gate  * ip_resume() - Nothing to do, always okay
6747c478bd9Sstevel@tonic-gate  */
6757c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6767c478bd9Sstevel@tonic-gate static int
ip_resume(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)6777c478bd9Sstevel@tonic-gate ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
67846fbc806SToomas Soome     char **errorp, rcm_info_t ** depend_info)
6797c478bd9Sstevel@tonic-gate {
6807c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
6817c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
6827c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
6837c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
6847c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
6857c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc);
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate /*
6937c478bd9Sstevel@tonic-gate  * ip_remove() - remove a resource from cache
6947c478bd9Sstevel@tonic-gate  */
6957c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6967c478bd9Sstevel@tonic-gate static int
ip_remove(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,rcm_info_t ** depend_info)6977c478bd9Sstevel@tonic-gate ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
69846fbc806SToomas Soome     char **errorp, rcm_info_t **depend_info)
6997c478bd9Sstevel@tonic-gate {
7007c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
7037c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
7047c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
7057c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
7067c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
7077c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc);
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
7127c478bd9Sstevel@tonic-gate 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
7137c478bd9Sstevel@tonic-gate 	if (!node) {
7147c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_INFO,
7157c478bd9Sstevel@tonic-gate 		    _("IP: remove(%s) unrecognized resource\n"), rsrc);
7167c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
7177c478bd9Sstevel@tonic-gate 		errno = ENOENT;
7187c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
7197c478bd9Sstevel@tonic-gate 	}
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	/* remove the cached entry for the resource */
7227c478bd9Sstevel@tonic-gate 	cache_remove(node);
723392b1d6eSyz 	free_node(node);
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
7267c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate /*
7307c478bd9Sstevel@tonic-gate  * ip_notify_event - Project private implementation to receive new resource
7317c478bd9Sstevel@tonic-gate  *		   events. It intercepts all new resource events. If the
7327c478bd9Sstevel@tonic-gate  *		   new resource is a network resource, pass up a notify
7337c478bd9Sstevel@tonic-gate  *		   for it too. The new resource need not be cached, since
7347c478bd9Sstevel@tonic-gate  *		   it is done at register again.
7357c478bd9Sstevel@tonic-gate  */
7367c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7377c478bd9Sstevel@tonic-gate static int
ip_notify_event(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,nvlist_t * nvl,rcm_info_t ** depend_info)7387c478bd9Sstevel@tonic-gate ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
73946fbc806SToomas Soome     char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
7407c478bd9Sstevel@tonic-gate {
741d62bc4baSyz 	datalink_id_t	linkid;
742d62bc4baSyz 	nvpair_t *nvp = NULL;
743d62bc4baSyz 	uint64_t id64;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
7467c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
7477c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
7487c478bd9Sstevel@tonic-gate 	assert(nvl != NULL);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc);
7517c478bd9Sstevel@tonic-gate 
752d62bc4baSyz 	if (!STREQ(rsrc, RCM_RESOURCE_LINK_NEW)) {
7537c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_INFO,
7547c478bd9Sstevel@tonic-gate 		    _("IP: unrecognized event for %s\n"), rsrc);
7557c478bd9Sstevel@tonic-gate 		ip_log_err(NULL, errorp, "unrecognized event");
7567c478bd9Sstevel@tonic-gate 		errno = EINVAL;
7577c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
7587c478bd9Sstevel@tonic-gate 	}
7597c478bd9Sstevel@tonic-gate 
760d62bc4baSyz 	/* Update cache to reflect latest interfaces */
7617c478bd9Sstevel@tonic-gate 	if (update_cache(hd) < 0) {
7627c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n"));
7637c478bd9Sstevel@tonic-gate 		ip_log_err(NULL, errorp, "Private Cache update failed");
7647c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
7657c478bd9Sstevel@tonic-gate 	}
7667c478bd9Sstevel@tonic-gate 
767d62bc4baSyz 	rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n");
768d62bc4baSyz 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
769d62bc4baSyz 		if (STREQ(nvpair_name(nvp), RCM_NV_LINKID)) {
770d62bc4baSyz 			if (nvpair_value_uint64(nvp, &id64) != 0) {
771d62bc4baSyz 				rcm_log_message(RCM_WARNING,
772d62bc4baSyz 				    _("IP: cannot get linkid\n"));
773d62bc4baSyz 				return (RCM_FAILURE);
774d62bc4baSyz 			}
775d62bc4baSyz 			linkid = (datalink_id_t)id64;
7766e91bba0SGirish Moodalbail 			/*
7776e91bba0SGirish Moodalbail 			 * Grovel through /etc/hostname* files and configure
7786e91bba0SGirish Moodalbail 			 * interface in the same way that they would be handled
7796e91bba0SGirish Moodalbail 			 * by network/physical.
7806e91bba0SGirish Moodalbail 			 */
7816e91bba0SGirish Moodalbail 			if (if_configure_hostname(linkid) != 0) {
7826e91bba0SGirish Moodalbail 				rcm_log_message(RCM_ERROR,
7836e91bba0SGirish Moodalbail 				    _("IP: Configuration failed (%u)\n"),
7846e91bba0SGirish Moodalbail 				    linkid);
7856e91bba0SGirish Moodalbail 				ip_log_err(NULL, errorp,
7866e91bba0SGirish Moodalbail 				    "Failed configuring one or more IP "
7876e91bba0SGirish Moodalbail 				    "addresses");
7886e91bba0SGirish Moodalbail 			}
7896e91bba0SGirish Moodalbail 
7906e91bba0SGirish Moodalbail 			/*
7916e91bba0SGirish Moodalbail 			 * Query libipadm for persistent configuration info
7926e91bba0SGirish Moodalbail 			 * and resurrect that persistent configuration.
7936e91bba0SGirish Moodalbail 			 */
7946e91bba0SGirish Moodalbail 			if (if_configure_ipadm(linkid) != 0) {
795d62bc4baSyz 				rcm_log_message(RCM_ERROR,
796d62bc4baSyz 				    _("IP: Configuration failed (%u)\n"),
797d62bc4baSyz 				    linkid);
798d62bc4baSyz 				ip_log_err(NULL, errorp,
799d62bc4baSyz 				    "Failed configuring one or more IP "
800d62bc4baSyz 				    "addresses");
8017c478bd9Sstevel@tonic-gate 			}
8027c478bd9Sstevel@tonic-gate 
803d62bc4baSyz 			/* Notify all IP address consumers */
804d62bc4baSyz 			ip_consumer_notify(hd, linkid, errorp, flags,
805d62bc4baSyz 			    depend_info);
806d62bc4baSyz 		}
8077c478bd9Sstevel@tonic-gate 	}
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1,
8107c478bd9Sstevel@tonic-gate 	    "IP: notify_event: device configuration complete\n");
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate /*
8167c478bd9Sstevel@tonic-gate  * ip_usage - Determine the usage of a device.  Call with cache_lock held.
8177c478bd9Sstevel@tonic-gate  *	    The returned buffer is owned by caller, and the caller
8187c478bd9Sstevel@tonic-gate  *	    must free it up when done.
8197c478bd9Sstevel@tonic-gate  */
8207c478bd9Sstevel@tonic-gate static char *
ip_usage(ip_cache_t * node)8217c478bd9Sstevel@tonic-gate ip_usage(ip_cache_t *node)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
824e11c3f44Smeem 	uint_t numup;
825e11c3f44Smeem 	char *sep, *buf, *linkidstr;
826d62bc4baSyz 	datalink_id_t linkid;
827e11c3f44Smeem 	const char *msg;
828d62bc4baSyz 	char link[MAXLINKNAMELEN];
8297c478bd9Sstevel@tonic-gate 	char addrstr[INET6_ADDRSTRLEN];
830d62bc4baSyz 	char errmsg[DLADM_STRSIZE];
831d62bc4baSyz 	dladm_status_t status;
832e11c3f44Smeem 	boolean_t offline, ipmp;
833e11c3f44Smeem 	size_t bufsz = 0;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource);
8367c478bd9Sstevel@tonic-gate 
837d62bc4baSyz 	/*
838d62bc4baSyz 	 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid>
839d62bc4baSyz 	 */
840d62bc4baSyz 	linkidstr = strchr(node->ip_resource, '/');
841d62bc4baSyz 	assert(linkidstr != NULL);
842d62bc4baSyz 	linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource;
843d62bc4baSyz 
844d62bc4baSyz 	errno = 0;
845d62bc4baSyz 	linkid = strtol(linkidstr, &buf, 10);
846d62bc4baSyz 	if (errno != 0 || *buf != '\0') {
847d62bc4baSyz 		rcm_log_message(RCM_ERROR,
848d62bc4baSyz 		    _("IP: usage(%s) parse linkid failure (%s)\n"),
849d62bc4baSyz 		    node->ip_resource, strerror(errno));
850d62bc4baSyz 		return (NULL);
851d62bc4baSyz 	}
852d62bc4baSyz 
8534ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL, NULL,
8544ac67f02SAnurag S. Maskey 	    NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
855d62bc4baSyz 		rcm_log_message(RCM_ERROR,
856d62bc4baSyz 		    _("IP: usage(%s) get link name failure(%s)\n"),
857d62bc4baSyz 		    node->ip_resource, dladm_status2str(status, errmsg));
858d62bc4baSyz 		return (NULL);
859d62bc4baSyz 	}
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	/* TRANSLATION_NOTE: separator used between IP addresses */
8627c478bd9Sstevel@tonic-gate 	sep = _(", ");
8637c478bd9Sstevel@tonic-gate 
864e11c3f44Smeem 	numup = 0;
865e11c3f44Smeem 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next)
866e11c3f44Smeem 		if (lif->li_ifflags & IFF_UP)
867e11c3f44Smeem 			numup++;
8687c478bd9Sstevel@tonic-gate 
869e11c3f44Smeem 	ipmp = (node->ip_pif->pi_grname[0] != '\0');
870e11c3f44Smeem 	offline = ((node->ip_cachestate & CACHE_IF_OFFLINED) != 0);
8717c478bd9Sstevel@tonic-gate 
872e11c3f44Smeem 	if (offline) {
873e11c3f44Smeem 		msg = _("offlined");
874e11c3f44Smeem 	} else if (numup == 0) {
875e11c3f44Smeem 		msg = _("plumbed but down");
8767c478bd9Sstevel@tonic-gate 	} else {
877e11c3f44Smeem 		if (ipmp) {
878e11c3f44Smeem 			msg = _("providing connectivity for IPMP group ");
879e11c3f44Smeem 			bufsz += LIFGRNAMSIZ;
880e11c3f44Smeem 		} else {
881e11c3f44Smeem 			msg = _("hosts IP addresses: ");
882e11c3f44Smeem 			bufsz += (numup * (INET6_ADDRSTRLEN + strlen(sep)));
883e11c3f44Smeem 		}
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate 
886e11c3f44Smeem 	bufsz += strlen(link) + strlen(msg) + 1;
8877c478bd9Sstevel@tonic-gate 	if ((buf = malloc(bufsz)) == NULL) {
8887c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
8897c478bd9Sstevel@tonic-gate 		    _("IP: usage(%s) malloc failure(%s)\n"),
8907c478bd9Sstevel@tonic-gate 		    node->ip_resource, strerror(errno));
8917c478bd9Sstevel@tonic-gate 		return (NULL);
8927c478bd9Sstevel@tonic-gate 	}
893e11c3f44Smeem 	(void) snprintf(buf, bufsz, "%s: %s", link, msg);
8947c478bd9Sstevel@tonic-gate 
895e11c3f44Smeem 	if (!offline && numup > 0) {
896e11c3f44Smeem 		if (ipmp) {
897e11c3f44Smeem 			(void) strlcat(buf, node->ip_pif->pi_grname, bufsz);
8987c478bd9Sstevel@tonic-gate 		} else {
899e11c3f44Smeem 			lif = node->ip_pif->pi_lifs;
900e11c3f44Smeem 			for (; lif != NULL; lif = lif->li_next) {
901e11c3f44Smeem 				if (!(lif->li_ifflags & IFF_UP))
902e11c3f44Smeem 					continue;
9037c478bd9Sstevel@tonic-gate 
904e11c3f44Smeem 				if (!ip_addrstr(lif, addrstr, sizeof (addrstr)))
905e11c3f44Smeem 					continue;
906e11c3f44Smeem 
907e11c3f44Smeem 				(void) strlcat(buf, addrstr, bufsz);
908e11c3f44Smeem 				if (--numup > 0)
909e11c3f44Smeem 					(void) strlcat(buf, sep, bufsz);
910e11c3f44Smeem 			}
9117c478bd9Sstevel@tonic-gate 		}
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
9157c478bd9Sstevel@tonic-gate 	    node->ip_resource, buf);
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	return (buf);
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate 
920e11c3f44Smeem static boolean_t
ip_addrstr(ip_lif_t * lif,char * addrstr,size_t addrsize)921e11c3f44Smeem ip_addrstr(ip_lif_t *lif, char *addrstr, size_t addrsize)
922e11c3f44Smeem {
923e11c3f44Smeem 	int af = lif->li_addr.family;
924e11c3f44Smeem 	void *addr;
925e11c3f44Smeem 
926e11c3f44Smeem 	if (af == AF_INET6) {
927e11c3f44Smeem 		addr = &lif->li_addr.ip6.sin6_addr;
928e11c3f44Smeem 	} else if (af == AF_INET) {
929e11c3f44Smeem 		addr = &lif->li_addr.ip4.sin_addr;
930e11c3f44Smeem 	} else {
931e11c3f44Smeem 		rcm_log_message(RCM_DEBUG,
932e11c3f44Smeem 		    "IP: unknown addr family %d, assuming AF_INET\n", af);
933e11c3f44Smeem 		af = AF_INET;
934e11c3f44Smeem 		addr = &lif->li_addr.ip4.sin_addr;
935e11c3f44Smeem 	}
936e11c3f44Smeem 	if (inet_ntop(af, addr, addrstr, addrsize) == NULL) {
937e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
938e11c3f44Smeem 		    _("IP: inet_ntop: %s\n"), strerror(errno));
939e11c3f44Smeem 		return (B_FALSE);
940e11c3f44Smeem 	}
941e11c3f44Smeem 
942e11c3f44Smeem 	rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr);
943e11c3f44Smeem 	return (B_TRUE);
944e11c3f44Smeem }
945e11c3f44Smeem 
9467c478bd9Sstevel@tonic-gate /*
9477c478bd9Sstevel@tonic-gate  * Cache management routines, all cache management functions should be
9487c478bd9Sstevel@tonic-gate  * be called with cache_lock held.
9497c478bd9Sstevel@tonic-gate  */
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate /*
952d62bc4baSyz  * cache_lookup() - Get a cache node for a resource.
9537c478bd9Sstevel@tonic-gate  *		  Call with cache lock held.
9547c478bd9Sstevel@tonic-gate  *
9557c478bd9Sstevel@tonic-gate  * This ensures that the cache is consistent with the system state and
9567c478bd9Sstevel@tonic-gate  * returns a pointer to the cache element corresponding to the resource.
9577c478bd9Sstevel@tonic-gate  */
9587c478bd9Sstevel@tonic-gate static ip_cache_t *
cache_lookup(rcm_handle_t * hd,char * rsrc,char options)9597c478bd9Sstevel@tonic-gate cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
9607c478bd9Sstevel@tonic-gate {
9617c478bd9Sstevel@tonic-gate 	ip_cache_t *probe;
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc);
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	if ((options & CACHE_REFRESH) && (hd != NULL)) {
9667c478bd9Sstevel@tonic-gate 		/* drop lock since update locks cache again */
9677c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
9687c478bd9Sstevel@tonic-gate 		(void) update_cache(hd);
9697c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&cache_lock);
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	probe = cache_head.ip_next;
9737c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
9747c478bd9Sstevel@tonic-gate 		if (probe->ip_resource &&
975d62bc4baSyz 		    STREQ(rsrc, probe->ip_resource)) {
9767c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE2,
9777c478bd9Sstevel@tonic-gate 			    "IP: cache lookup success(%s)\n", rsrc);
9787c478bd9Sstevel@tonic-gate 			return (probe);
9797c478bd9Sstevel@tonic-gate 		}
9807c478bd9Sstevel@tonic-gate 		probe = probe->ip_next;
9817c478bd9Sstevel@tonic-gate 	}
9827c478bd9Sstevel@tonic-gate 	return (NULL);
9837c478bd9Sstevel@tonic-gate }
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate /*
9867c478bd9Sstevel@tonic-gate  * free_node - Free a node from the cache
9877c478bd9Sstevel@tonic-gate  *	     Call with cache_lock held.
9887c478bd9Sstevel@tonic-gate  */
9897c478bd9Sstevel@tonic-gate static void
free_node(ip_cache_t * node)9907c478bd9Sstevel@tonic-gate free_node(ip_cache_t *node)
9917c478bd9Sstevel@tonic-gate {
9927c478bd9Sstevel@tonic-gate 	ip_pif_t *pif;
9937c478bd9Sstevel@tonic-gate 	ip_lif_t *lif, *tmplif;
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	if (node) {
9967c478bd9Sstevel@tonic-gate 		if (node->ip_resource) {
9977c478bd9Sstevel@tonic-gate 			free(node->ip_resource);
9987c478bd9Sstevel@tonic-gate 		}
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 		/* free the pif */
10017c478bd9Sstevel@tonic-gate 		pif = node->ip_pif;
10027c478bd9Sstevel@tonic-gate 		if (pif) {
10037c478bd9Sstevel@tonic-gate 			/* free logical interfaces */
10047c478bd9Sstevel@tonic-gate 			lif = pif->pi_lifs;
10057c478bd9Sstevel@tonic-gate 			while (lif) {
10067c478bd9Sstevel@tonic-gate 				tmplif = lif->li_next;
10077c478bd9Sstevel@tonic-gate 				free(lif);
10087c478bd9Sstevel@tonic-gate 				lif = tmplif;
10097c478bd9Sstevel@tonic-gate 			}
10107c478bd9Sstevel@tonic-gate 			free(pif);
10117c478bd9Sstevel@tonic-gate 		}
10127c478bd9Sstevel@tonic-gate 		free(node);
10137c478bd9Sstevel@tonic-gate 	}
10147c478bd9Sstevel@tonic-gate }
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate /*
10177c478bd9Sstevel@tonic-gate  * cache_insert - Insert a resource node in cache
10187c478bd9Sstevel@tonic-gate  *		Call with the cache_lock held.
10197c478bd9Sstevel@tonic-gate  */
10207c478bd9Sstevel@tonic-gate static void
cache_insert(ip_cache_t * node)10217c478bd9Sstevel@tonic-gate cache_insert(ip_cache_t *node)
10227c478bd9Sstevel@tonic-gate {
1023d62bc4baSyz 	rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n",
1024d62bc4baSyz 	    node->ip_resource);
1025d62bc4baSyz 
10267c478bd9Sstevel@tonic-gate 	/* insert at the head for best performance */
10277c478bd9Sstevel@tonic-gate 	node->ip_next = cache_head.ip_next;
10287c478bd9Sstevel@tonic-gate 	node->ip_prev = &cache_head;
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	node->ip_next->ip_prev = node;
10317c478bd9Sstevel@tonic-gate 	node->ip_prev->ip_next = node;
10327c478bd9Sstevel@tonic-gate }
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate /*
10357c478bd9Sstevel@tonic-gate  * cache_remove() - Remove a resource node from cache.
10367c478bd9Sstevel@tonic-gate  *		  Call with the cache_lock held.
10377c478bd9Sstevel@tonic-gate  */
10387c478bd9Sstevel@tonic-gate static void
cache_remove(ip_cache_t * node)10397c478bd9Sstevel@tonic-gate cache_remove(ip_cache_t *node)
10407c478bd9Sstevel@tonic-gate {
1041d62bc4baSyz 	rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n",
1042d62bc4baSyz 	    node->ip_resource);
1043d62bc4baSyz 
10447c478bd9Sstevel@tonic-gate 	node->ip_next->ip_prev = node->ip_prev;
10457c478bd9Sstevel@tonic-gate 	node->ip_prev->ip_next = node->ip_next;
10467c478bd9Sstevel@tonic-gate 	node->ip_next = NULL;
10477c478bd9Sstevel@tonic-gate 	node->ip_prev = NULL;
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate /*
10517c478bd9Sstevel@tonic-gate  * update_pif() - Update physical interface properties
10527c478bd9Sstevel@tonic-gate  *		Call with cache_lock held
10537c478bd9Sstevel@tonic-gate  */
10546e91bba0SGirish Moodalbail int
update_pif(rcm_handle_t * hd,int af,int sock,struct ifaddrs * ifa)10556e91bba0SGirish Moodalbail update_pif(rcm_handle_t *hd, int af, int sock, struct ifaddrs *ifa)
10567c478bd9Sstevel@tonic-gate {
1057d62bc4baSyz 	char *rsrc;
1058595aa6e4Smeem 	ifspec_t ifspec;
10597c478bd9Sstevel@tonic-gate 	ushort_t ifnumber = 0;
10607c478bd9Sstevel@tonic-gate 	ip_cache_t *probe;
10617c478bd9Sstevel@tonic-gate 	ip_pif_t pif;
10627c478bd9Sstevel@tonic-gate 	ip_pif_t *probepif;
10637c478bd9Sstevel@tonic-gate 	ip_lif_t *probelif;
10647c478bd9Sstevel@tonic-gate 	struct lifreq lifreq;
10657c478bd9Sstevel@tonic-gate 	struct sockaddr_storage ifaddr;
10667c478bd9Sstevel@tonic-gate 	uint64_t ifflags;
10677c478bd9Sstevel@tonic-gate 	int lif_listed = 0;
10687c478bd9Sstevel@tonic-gate 
10696e91bba0SGirish Moodalbail 	rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", ifa->ifa_name);
10707c478bd9Sstevel@tonic-gate 
10716e91bba0SGirish Moodalbail 	if (!ifparse_ifspec(ifa->ifa_name, &ifspec)) {
1072595aa6e4Smeem 		rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"),
10736e91bba0SGirish Moodalbail 		    ifa->ifa_name);
1074595aa6e4Smeem 		return (-1);
10757c478bd9Sstevel@tonic-gate 	}
10767c478bd9Sstevel@tonic-gate 
1077595aa6e4Smeem 	(void) snprintf(pif.pi_ifname, sizeof (pif.pi_ifname), "%s%d",
1078595aa6e4Smeem 	    ifspec.ifsp_devnm, ifspec.ifsp_ppa);
1079595aa6e4Smeem 	if (ifspec.ifsp_lunvalid)
1080595aa6e4Smeem 		ifnumber = ifspec.ifsp_lun;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	/* Get the interface flags */
10836e91bba0SGirish Moodalbail 	ifflags = ifa->ifa_flags;
10847c478bd9Sstevel@tonic-gate 
10858de9d095Syz 	/*
10868de9d095Syz 	 * Ignore interfaces that are always incapable of DR:
10878de9d095Syz 	 *   - IFF_VIRTUAL:	e.g., loopback and vni
10888de9d095Syz 	 *   - IFF_POINTOPOINT:	e.g., sppp and ip.tun
10898de9d095Syz 	 *   - !IFF_MULTICAST:	e.g., ip.6to4tun
1090e11c3f44Smeem 	 *   - IFF_IPMP:	IPMP meta-interfaces
10918de9d095Syz 	 *
10928de9d095Syz 	 * Note: The !IFF_MULTICAST check can be removed once iptun is
10938de9d095Syz 	 * implemented as a datalink.
10948de9d095Syz 	 */
10958de9d095Syz 	if (!(ifflags & IFF_MULTICAST) ||
1096e11c3f44Smeem 	    (ifflags & (IFF_POINTOPOINT | IFF_VIRTUAL | IFF_IPMP))) {
1097595aa6e4Smeem 		rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n",
1098595aa6e4Smeem 		    pif.pi_ifname);
10997c478bd9Sstevel@tonic-gate 		return (0);
11007c478bd9Sstevel@tonic-gate 	}
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	/* Get the interface group name for this interface */
11036e91bba0SGirish Moodalbail 	bzero(&lifreq, sizeof (lifreq));
11046e91bba0SGirish Moodalbail 	(void) strncpy(lifreq.lifr_name, ifa->ifa_name, LIFNAMSIZ);
11056e91bba0SGirish Moodalbail 
11067c478bd9Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) {
1107e11c3f44Smeem 		if (errno != ENXIO) {
1108e11c3f44Smeem 			rcm_log_message(RCM_ERROR,
1109e11c3f44Smeem 			    _("IP: SIOCGLIFGROUPNAME(%s): %s\n"),
1110e11c3f44Smeem 			    lifreq.lifr_name, strerror(errno));
1111e11c3f44Smeem 		}
11127c478bd9Sstevel@tonic-gate 		return (-1);
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	/* copy the group name */
1116e11c3f44Smeem 	(void) strlcpy(pif.pi_grname, lifreq.lifr_groupname,
1117e11c3f44Smeem 	    sizeof (pif.pi_grname));
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	/* Get the interface address for this interface */
112064639aafSDarren Reed 	(void) memcpy(&ifaddr, ifa->ifa_addr, sizeof (ifaddr));
11217c478bd9Sstevel@tonic-gate 
1122d62bc4baSyz 	rsrc = get_link_resource(pif.pi_ifname);
1123d62bc4baSyz 	if (rsrc == NULL) {
1124d62bc4baSyz 		rcm_log_message(RCM_ERROR,
1125d62bc4baSyz 		    _("IP: get_link_resource(%s) failed\n"),
1126d62bc4baSyz 		    lifreq.lifr_name);
1127d62bc4baSyz 		return (-1);
1128d62bc4baSyz 	}
11297c478bd9Sstevel@tonic-gate 
1130d62bc4baSyz 	probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
11317c478bd9Sstevel@tonic-gate 	if (probe != NULL) {
1132d62bc4baSyz 		free(rsrc);
11337c478bd9Sstevel@tonic-gate 		probe->ip_cachestate &= ~(CACHE_IF_STALE);
11347c478bd9Sstevel@tonic-gate 	} else {
11357c478bd9Sstevel@tonic-gate 		if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) {
11367c478bd9Sstevel@tonic-gate 			/* malloc errors are bad */
1137d62bc4baSyz 			free(rsrc);
11387c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
11397c478bd9Sstevel@tonic-gate 			    strerror(errno));
11407c478bd9Sstevel@tonic-gate 			return (-1);
11417c478bd9Sstevel@tonic-gate 		}
11427c478bd9Sstevel@tonic-gate 
1143d62bc4baSyz 		probe->ip_resource = rsrc;
11447c478bd9Sstevel@tonic-gate 		probe->ip_pif = NULL;
11457c478bd9Sstevel@tonic-gate 		probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY;
11467c478bd9Sstevel@tonic-gate 		probe->ip_cachestate |= CACHE_IF_NEW;
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 		cache_insert(probe);
11497c478bd9Sstevel@tonic-gate 	}
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	probepif = probe->ip_pif;
11527c478bd9Sstevel@tonic-gate 	if (probepif != NULL) {
11537c478bd9Sstevel@tonic-gate 		/* Check if lifs need to be updated */
11547c478bd9Sstevel@tonic-gate 		probelif = probepif->pi_lifs;
11557c478bd9Sstevel@tonic-gate 		while (probelif != NULL) {
11567c478bd9Sstevel@tonic-gate 			if ((probelif->li_ifnum == ifnumber) &&
11577c478bd9Sstevel@tonic-gate 			    (probelif->li_addr.family == ifaddr.ss_family)) {
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_TRACE2,
11607c478bd9Sstevel@tonic-gate 				    "IP: refreshing lifs for %s, ifnum=%d\n",
11617c478bd9Sstevel@tonic-gate 				    pif.pi_ifname, probelif->li_ifnum);
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 				/* refresh lif properties */
11647c478bd9Sstevel@tonic-gate 				(void) memcpy(&probelif->li_addr, &ifaddr,
11657c478bd9Sstevel@tonic-gate 				    sizeof (probelif->li_addr));
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 				probelif->li_ifflags = ifflags;
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 				lif_listed++;
11707c478bd9Sstevel@tonic-gate 				probelif->li_cachestate &= ~(CACHE_IF_STALE);
11717c478bd9Sstevel@tonic-gate 				break;
11727c478bd9Sstevel@tonic-gate 			}
11737c478bd9Sstevel@tonic-gate 			probelif = probelif->li_next;
11747c478bd9Sstevel@tonic-gate 		}
11757c478bd9Sstevel@tonic-gate 	}
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	if (probepif == NULL) {
11787c478bd9Sstevel@tonic-gate 		if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) {
11797c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
11807c478bd9Sstevel@tonic-gate 			    strerror(errno));
11817c478bd9Sstevel@tonic-gate 			if (probe->ip_pif == NULL) {
11827c478bd9Sstevel@tonic-gate 				/* we created it, so clean it up */
11837c478bd9Sstevel@tonic-gate 				free(probe);
11847c478bd9Sstevel@tonic-gate 			}
11857c478bd9Sstevel@tonic-gate 			return (-1);
11867c478bd9Sstevel@tonic-gate 		}
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 		probe->ip_pif = probepif;
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 		/* Save interface name */
11917c478bd9Sstevel@tonic-gate 		(void) memcpy(&probepif->pi_ifname, &pif.pi_ifname,
11927c478bd9Sstevel@tonic-gate 		    sizeof (pif.pi_ifname));
11937c478bd9Sstevel@tonic-gate 	}
11947c478bd9Sstevel@tonic-gate 
1195e11c3f44Smeem 	/* save the group name */
1196e11c3f44Smeem 	(void) strlcpy(probepif->pi_grname, pif.pi_grname,
1197e11c3f44Smeem 	    sizeof (pif.pi_grname));
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	/* add lif, if this is a lif and it is not in cache */
12007c478bd9Sstevel@tonic-gate 	if (!lif_listed) {
12017c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n",
12027c478bd9Sstevel@tonic-gate 		    pif.pi_ifname);
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 		if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) {
12057c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
12067c478bd9Sstevel@tonic-gate 			    strerror(errno));
12077c478bd9Sstevel@tonic-gate 			return (-1);
12087c478bd9Sstevel@tonic-gate 		}
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 		/* save lif properties */
12117c478bd9Sstevel@tonic-gate 		(void) memcpy(&probelif->li_addr, &ifaddr,
12127c478bd9Sstevel@tonic-gate 		    sizeof (probelif->li_addr));
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 		probelif->li_ifnum = ifnumber;
12157c478bd9Sstevel@tonic-gate 		probelif->li_ifflags = ifflags;
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 		/* insert us at the head of the lif list */
12187c478bd9Sstevel@tonic-gate 		probelif->li_next = probepif->pi_lifs;
12197c478bd9Sstevel@tonic-gate 		if (probelif->li_next != NULL) {
12207c478bd9Sstevel@tonic-gate 			probelif->li_next->li_prev = probelif;
12217c478bd9Sstevel@tonic-gate 		}
12227c478bd9Sstevel@tonic-gate 		probelif->li_prev = NULL;
12237c478bd9Sstevel@tonic-gate 		probelif->li_pif = probepif;
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 		probepif->pi_lifs = probelif;
12267c478bd9Sstevel@tonic-gate 	}
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n",
12297c478bd9Sstevel@tonic-gate 	    probe->ip_resource);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	return (0);
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate /*
12357c478bd9Sstevel@tonic-gate  * update_ipifs() - Determine all network interfaces in the system
12367c478bd9Sstevel@tonic-gate  *		  Call with cache_lock held
12377c478bd9Sstevel@tonic-gate  */
12387c478bd9Sstevel@tonic-gate static int
update_ipifs(rcm_handle_t * hd,int af)12397c478bd9Sstevel@tonic-gate update_ipifs(rcm_handle_t *hd, int af)
12407c478bd9Sstevel@tonic-gate {
12417c478bd9Sstevel@tonic-gate 
12426e91bba0SGirish Moodalbail 	struct ifaddrs *ifa;
12436e91bba0SGirish Moodalbail 	ipadm_addr_info_t *ainfo;
12446e91bba0SGirish Moodalbail 	ipadm_addr_info_t *ptr;
12456e91bba0SGirish Moodalbail 	ipadm_status_t status;
12466e91bba0SGirish Moodalbail 	int sock;
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
12497c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
12507c478bd9Sstevel@tonic-gate 		    _("IP: failure opening %s socket: %s\n"),
12517c478bd9Sstevel@tonic-gate 		    af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
12527c478bd9Sstevel@tonic-gate 		return (-1);
12537c478bd9Sstevel@tonic-gate 	}
12547c478bd9Sstevel@tonic-gate 
12556e91bba0SGirish Moodalbail 	status = ipadm_addr_info(ip_handle, NULL, &ainfo, IPADM_OPT_ZEROADDR,
12566e91bba0SGirish Moodalbail 	    LIFC_UNDER_IPMP);
12576e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS) {
12587c478bd9Sstevel@tonic-gate 		(void) close(sock);
12597c478bd9Sstevel@tonic-gate 		return (-1);
12607c478bd9Sstevel@tonic-gate 	}
12616e91bba0SGirish Moodalbail 	for (ptr = ainfo; ptr; ptr = IA_NEXT(ptr)) {
12626e91bba0SGirish Moodalbail 		ifa = &ptr->ia_ifa;
12636e91bba0SGirish Moodalbail 		if (ptr->ia_state != IFA_DISABLED &&
126464639aafSDarren Reed 		    af == ifa->ifa_addr->sa_family)
12656e91bba0SGirish Moodalbail 			(void) update_pif(hd, af, sock, ifa);
12667c478bd9Sstevel@tonic-gate 	}
12677c478bd9Sstevel@tonic-gate 	(void) close(sock);
12686e91bba0SGirish Moodalbail 	ipadm_free_addr_info(ainfo);
12697c478bd9Sstevel@tonic-gate 	return (0);
12707c478bd9Sstevel@tonic-gate }
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate /*
12737c478bd9Sstevel@tonic-gate  * update_cache() - Update cache with latest interface info
12747c478bd9Sstevel@tonic-gate  */
12757c478bd9Sstevel@tonic-gate static int
update_cache(rcm_handle_t * hd)12767c478bd9Sstevel@tonic-gate update_cache(rcm_handle_t *hd)
12777c478bd9Sstevel@tonic-gate {
12787c478bd9Sstevel@tonic-gate 	ip_cache_t *probe;
12797c478bd9Sstevel@tonic-gate 	struct ip_lif *lif;
12807c478bd9Sstevel@tonic-gate 	struct ip_lif *nextlif;
12817c478bd9Sstevel@tonic-gate 	int rv;
12827c478bd9Sstevel@tonic-gate 	int i;
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: update_cache\n");
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	/* first we walk the entire cache, marking each entry stale */
12897c478bd9Sstevel@tonic-gate 	probe = cache_head.ip_next;
12907c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
12917c478bd9Sstevel@tonic-gate 		probe->ip_cachestate |= CACHE_IF_STALE;
12927c478bd9Sstevel@tonic-gate 		if ((probe->ip_pif != NULL) &&
12937c478bd9Sstevel@tonic-gate 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
12947c478bd9Sstevel@tonic-gate 			while (lif != NULL) {
12957c478bd9Sstevel@tonic-gate 				lif->li_cachestate |= CACHE_IF_STALE;
12967c478bd9Sstevel@tonic-gate 				lif = lif->li_next;
12977c478bd9Sstevel@tonic-gate 			}
12987c478bd9Sstevel@tonic-gate 		}
12997c478bd9Sstevel@tonic-gate 		probe = probe->ip_next;
13007c478bd9Sstevel@tonic-gate 	}
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n");
13037c478bd9Sstevel@tonic-gate 	if (update_ipifs(hd, AF_INET) < 0) {
13047c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
13057c478bd9Sstevel@tonic-gate 		return (-1);
13067c478bd9Sstevel@tonic-gate 	}
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n");
13097c478bd9Sstevel@tonic-gate 	if (update_ipifs(hd, AF_INET6) < 0) {
13107c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
13117c478bd9Sstevel@tonic-gate 		return (-1);
13127c478bd9Sstevel@tonic-gate 	}
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	probe = cache_head.ip_next;
13157c478bd9Sstevel@tonic-gate 	/* unregister devices that are not offlined and still in cache */
13167c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
13177c478bd9Sstevel@tonic-gate 		ip_cache_t *freeit;
13187c478bd9Sstevel@tonic-gate 		if ((probe->ip_pif != NULL) &&
13197c478bd9Sstevel@tonic-gate 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
13207c478bd9Sstevel@tonic-gate 			/* clear stale lifs */
13217c478bd9Sstevel@tonic-gate 			while (lif != NULL) {
13227c478bd9Sstevel@tonic-gate 				if (lif->li_cachestate & CACHE_IF_STALE) {
13237c478bd9Sstevel@tonic-gate 					nextlif = lif->li_next;
13247c478bd9Sstevel@tonic-gate 					if (lif->li_prev != NULL)
13257c478bd9Sstevel@tonic-gate 						lif->li_prev->li_next = nextlif;
13267c478bd9Sstevel@tonic-gate 					if (nextlif != NULL)
13277c478bd9Sstevel@tonic-gate 						nextlif->li_prev = lif->li_prev;
13287c478bd9Sstevel@tonic-gate 					if (probe->ip_pif->pi_lifs == lif)
13297c478bd9Sstevel@tonic-gate 						probe->ip_pif->pi_lifs =
13307c478bd9Sstevel@tonic-gate 						    nextlif;
13317c478bd9Sstevel@tonic-gate 					for (i = 0; i < IP_MAX_MODS; i++) {
13327c478bd9Sstevel@tonic-gate 						free(lif->li_modules[i]);
13337c478bd9Sstevel@tonic-gate 					}
13347c478bd9Sstevel@tonic-gate 					free(lif->li_reconfig);
13357c478bd9Sstevel@tonic-gate 					free(lif);
13367c478bd9Sstevel@tonic-gate 					lif = nextlif;
13377c478bd9Sstevel@tonic-gate 				} else {
13387c478bd9Sstevel@tonic-gate 					lif = lif->li_next;
13397c478bd9Sstevel@tonic-gate 				}
13407c478bd9Sstevel@tonic-gate 			}
13417c478bd9Sstevel@tonic-gate 		}
13427c478bd9Sstevel@tonic-gate 		if ((probe->ip_cachestate & CACHE_IF_STALE) &&
13437c478bd9Sstevel@tonic-gate 		    !(probe->ip_cachestate & CACHE_IF_OFFLINED)) {
13447c478bd9Sstevel@tonic-gate 			(void) rcm_unregister_interest(hd, probe->ip_resource,
13457c478bd9Sstevel@tonic-gate 			    0);
13467c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
13477c478bd9Sstevel@tonic-gate 			    probe->ip_resource);
13487c478bd9Sstevel@tonic-gate 			freeit = probe;
13497c478bd9Sstevel@tonic-gate 			probe = probe->ip_next;
13507c478bd9Sstevel@tonic-gate 			cache_remove(freeit);
13517c478bd9Sstevel@tonic-gate 			free_node(freeit);
13527c478bd9Sstevel@tonic-gate 			continue;
13537c478bd9Sstevel@tonic-gate 		}
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 		if (!(probe->ip_cachestate & CACHE_IF_NEW)) {
13567c478bd9Sstevel@tonic-gate 			probe = probe->ip_next;
13577c478bd9Sstevel@tonic-gate 			continue;
13587c478bd9Sstevel@tonic-gate 		}
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 		rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL);
13617c478bd9Sstevel@tonic-gate 		if (rv != RCM_SUCCESS) {
13627c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
13637c478bd9Sstevel@tonic-gate 			    _("IP: failed to register %s\n"),
13647c478bd9Sstevel@tonic-gate 			    probe->ip_resource);
13657c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
13667c478bd9Sstevel@tonic-gate 			return (-1);
13677c478bd9Sstevel@tonic-gate 		} else {
13687c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
13697c478bd9Sstevel@tonic-gate 			    probe->ip_resource);
13707c478bd9Sstevel@tonic-gate 			probe->ip_cachestate &= ~(CACHE_IF_NEW);
13717c478bd9Sstevel@tonic-gate 		}
13727c478bd9Sstevel@tonic-gate 		probe = probe->ip_next;
13737c478bd9Sstevel@tonic-gate 	}
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
13767c478bd9Sstevel@tonic-gate 	return (0);
13777c478bd9Sstevel@tonic-gate }
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate /*
13807c478bd9Sstevel@tonic-gate  * free_cache() - Empty the cache
13817c478bd9Sstevel@tonic-gate  */
13827c478bd9Sstevel@tonic-gate static void
free_cache()13837c478bd9Sstevel@tonic-gate free_cache()
13847c478bd9Sstevel@tonic-gate {
13857c478bd9Sstevel@tonic-gate 	ip_cache_t *probe;
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: free_cache\n");
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
13907c478bd9Sstevel@tonic-gate 	probe = cache_head.ip_next;
13917c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
13927c478bd9Sstevel@tonic-gate 		cache_remove(probe);
13937c478bd9Sstevel@tonic-gate 		free_node(probe);
13947c478bd9Sstevel@tonic-gate 		probe = cache_head.ip_next;
13957c478bd9Sstevel@tonic-gate 	}
13967c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
13977c478bd9Sstevel@tonic-gate }
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate /*
14007c478bd9Sstevel@tonic-gate  * ip_log_err() - RCM error log wrapper
14017c478bd9Sstevel@tonic-gate  */
14027c478bd9Sstevel@tonic-gate static void
ip_log_err(ip_cache_t * node,char ** errorp,char * errmsg)14037c478bd9Sstevel@tonic-gate ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
14047c478bd9Sstevel@tonic-gate {
1405d62bc4baSyz 	char *ifname = NULL;
1406e11c3f44Smeem 	int size;
14077c478bd9Sstevel@tonic-gate 	const char *errfmt;
1408e11c3f44Smeem 	char *error = NULL;
14097c478bd9Sstevel@tonic-gate 
1410*0c5967dbSToomas Soome 	if (node != NULL && node->ip_pif != NULL) {
1411d62bc4baSyz 		ifname = node->ip_pif->pi_ifname;
14127c478bd9Sstevel@tonic-gate 	}
14137c478bd9Sstevel@tonic-gate 
1414d62bc4baSyz 	if (ifname == NULL) {
14157c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg);
14167c478bd9Sstevel@tonic-gate 		errfmt = _("IP: %s");
1417e11c3f44Smeem 		size = strlen(errfmt) + strlen(errmsg) + 1;
1418e11c3f44Smeem 		if (errorp != NULL && (error = malloc(size)) != NULL)
1419e11c3f44Smeem 			(void) snprintf(error, size, errfmt, errmsg);
14207c478bd9Sstevel@tonic-gate 	} else {
1421d62bc4baSyz 		rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname);
14227c478bd9Sstevel@tonic-gate 		errfmt = _("IP: %s(%s)");
1423e11c3f44Smeem 		size = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1;
1424e11c3f44Smeem 		if (errorp != NULL && (error = malloc(size)) != NULL)
1425e11c3f44Smeem 			(void) snprintf(error, size, errfmt, errmsg, ifname);
14267c478bd9Sstevel@tonic-gate 	}
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	if (errorp != NULL)
14297c478bd9Sstevel@tonic-gate 		*errorp = error;
14307c478bd9Sstevel@tonic-gate }
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate /*
14337c478bd9Sstevel@tonic-gate  * if_cfginfo() - Save off the config info for all interfaces
14347c478bd9Sstevel@tonic-gate  */
14357c478bd9Sstevel@tonic-gate static int
if_cfginfo(ip_cache_t * node,uint_t force)14367c478bd9Sstevel@tonic-gate if_cfginfo(ip_cache_t *node, uint_t force)
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
14397c478bd9Sstevel@tonic-gate 	ip_pif_t *pif;
14407c478bd9Sstevel@tonic-gate 	int i;
14417c478bd9Sstevel@tonic-gate 	FILE *fp;
14427c478bd9Sstevel@tonic-gate 	char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
14437c478bd9Sstevel@tonic-gate 	char buf[MAX_RECONFIG_SIZE];
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource);
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	pif = node->ip_pif;
14487c478bd9Sstevel@tonic-gate 	lif = pif->pi_lifs;
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	while (lif != NULL) {
14517c478bd9Sstevel@tonic-gate 		/* Make a list of modules pushed and save */
14527c478bd9Sstevel@tonic-gate 		if (lif->li_ifnum == 0) {	/* physical instance */
14537c478bd9Sstevel@tonic-gate 			if (get_modlist(pif->pi_ifname, lif) == -1) {
14547c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_ERROR,
14557c478bd9Sstevel@tonic-gate 				    _("IP: get modlist error (%s) %s\n"),
14567c478bd9Sstevel@tonic-gate 				    pif->pi_ifname, strerror(errno));
1457e11c3f44Smeem 				clr_cfg_state(pif);
14587c478bd9Sstevel@tonic-gate 				return (-1);
14597c478bd9Sstevel@tonic-gate 			}
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 			if (!force) {
14627c478bd9Sstevel@tonic-gate 				/* Look if unknown modules have been inserted */
14637c478bd9Sstevel@tonic-gate 				for (i = (lif->li_modcnt - 2); i > 0; i--) {
14647c478bd9Sstevel@tonic-gate 					if (modop(pif->pi_ifname,
14657c478bd9Sstevel@tonic-gate 					    lif->li_modules[i],
14667c478bd9Sstevel@tonic-gate 					    i, MOD_CHECK) == -1) {
14677c478bd9Sstevel@tonic-gate 						rcm_log_message(RCM_ERROR,
14687c478bd9Sstevel@tonic-gate 						    _("IP: module %s@%d\n"),
14697c478bd9Sstevel@tonic-gate 						    lif->li_modules[i], i);
1470e11c3f44Smeem 						clr_cfg_state(pif);
14717c478bd9Sstevel@tonic-gate 						return (-1);
14727c478bd9Sstevel@tonic-gate 					}
14737c478bd9Sstevel@tonic-gate 				}
14747c478bd9Sstevel@tonic-gate 			}
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 			/* Last module is the device driver, so ignore that */
14777c478bd9Sstevel@tonic-gate 			for (i = (lif->li_modcnt - 2); i > 0; i--) {
14787c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_TRACE2,
14797c478bd9Sstevel@tonic-gate 				    "IP: modremove Pos = %d, Module = %s \n",
14807c478bd9Sstevel@tonic-gate 				    i, lif->li_modules[i]);
14817c478bd9Sstevel@tonic-gate 				if (modop(pif->pi_ifname, lif->li_modules[i],
14827c478bd9Sstevel@tonic-gate 				    i, MOD_REMOVE) == -1) {
14837c478bd9Sstevel@tonic-gate 					while (i != (lif->li_modcnt - 2)) {
14847c478bd9Sstevel@tonic-gate 						if (modop(pif->pi_ifname,
14857c478bd9Sstevel@tonic-gate 						    lif->li_modules[i],
14867c478bd9Sstevel@tonic-gate 						    i, MOD_INSERT) == -1) {
14877c478bd9Sstevel@tonic-gate 							/* Gross error */
14887c478bd9Sstevel@tonic-gate 							rcm_log_message(
14897c478bd9Sstevel@tonic-gate 							    RCM_ERROR,
14907c478bd9Sstevel@tonic-gate 							    _("IP: if_cfginfo"
14917c478bd9Sstevel@tonic-gate 							    "(%s) %s\n"),
14927c478bd9Sstevel@tonic-gate 							    pif->pi_ifname,
14937c478bd9Sstevel@tonic-gate 							    strerror(errno));
1494392b1d6eSyz 							clr_cfg_state(pif);
14957c478bd9Sstevel@tonic-gate 							return (-1);
14967c478bd9Sstevel@tonic-gate 						}
14977c478bd9Sstevel@tonic-gate 						i++;
14987c478bd9Sstevel@tonic-gate 					}
14997c478bd9Sstevel@tonic-gate 					rcm_log_message(
15007c478bd9Sstevel@tonic-gate 					    RCM_ERROR,
15017c478bd9Sstevel@tonic-gate 					    _("IP: if_cfginfo(%s): modremove "
15027c478bd9Sstevel@tonic-gate 					    "%s failed: %s\n"), pif->pi_ifname,
15037c478bd9Sstevel@tonic-gate 					    lif->li_modules[i],
15047c478bd9Sstevel@tonic-gate 					    strerror(errno));
1505392b1d6eSyz 					clr_cfg_state(pif);
15067c478bd9Sstevel@tonic-gate 					return (-1);
15077c478bd9Sstevel@tonic-gate 				}
15087c478bd9Sstevel@tonic-gate 			}
15097c478bd9Sstevel@tonic-gate 		}
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 		/* Save reconfiguration information */
15127c478bd9Sstevel@tonic-gate 		if (lif->li_ifflags & IFF_IPV4) {
15137c478bd9Sstevel@tonic-gate 			(void) snprintf(syscmd, sizeof (syscmd),
1514e11c3f44Smeem 			    "%s %s:%d configinfo\n", SBIN_IFCONFIG,
15157c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum);
15167c478bd9Sstevel@tonic-gate 		} else if (lif->li_ifflags & IFF_IPV6) {
15177c478bd9Sstevel@tonic-gate 			(void) snprintf(syscmd, sizeof (syscmd),
1518e11c3f44Smeem 			    "%s %s:%d inet6 configinfo\n", SBIN_IFCONFIG,
15197c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum);
15207c478bd9Sstevel@tonic-gate 		}
15217c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd);
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 		/* open a pipe to retrieve reconfiguration info */
15247c478bd9Sstevel@tonic-gate 		if ((fp = popen(syscmd, "r")) == NULL) {
15257c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
15267c478bd9Sstevel@tonic-gate 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
15277c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
1528e11c3f44Smeem 			clr_cfg_state(pif);
15297c478bd9Sstevel@tonic-gate 			return (-1);
15307c478bd9Sstevel@tonic-gate 		}
15317c478bd9Sstevel@tonic-gate 		bzero(buf, MAX_RECONFIG_SIZE);
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 		if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) {
15347c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
15357c478bd9Sstevel@tonic-gate 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
15367c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
15377c478bd9Sstevel@tonic-gate 			(void) pclose(fp);
1538e11c3f44Smeem 			clr_cfg_state(pif);
15397c478bd9Sstevel@tonic-gate 			return (-1);
15407c478bd9Sstevel@tonic-gate 		}
15417c478bd9Sstevel@tonic-gate 		(void) pclose(fp);
15427c478bd9Sstevel@tonic-gate 
1543e11c3f44Smeem 		if ((lif->li_reconfig = strdup(buf)) == NULL) {
15447c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
15457c478bd9Sstevel@tonic-gate 			    _("IP: malloc error (%s) %s\n"),
15467c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, strerror(errno));
1547e11c3f44Smeem 			clr_cfg_state(pif);
15487c478bd9Sstevel@tonic-gate 			return (-1);
15497c478bd9Sstevel@tonic-gate 		}
15507c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG,
15517c478bd9Sstevel@tonic-gate 		    "IP: if_cfginfo: reconfig string(%s:%d) = %s\n",
15527c478bd9Sstevel@tonic-gate 		    pif->pi_ifname, lif->li_ifnum, lif->li_reconfig);
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 		lif = lif->li_next;
15557c478bd9Sstevel@tonic-gate 	}
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 	return (0);
15587c478bd9Sstevel@tonic-gate }
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate /*
15617c478bd9Sstevel@tonic-gate  * if_unplumb() - Unplumb the interface
15627c478bd9Sstevel@tonic-gate  *		Save off the modlist, ifconfig options and unplumb.
15637c478bd9Sstevel@tonic-gate  *		Fail, if an unknown module lives between IP and driver and
15647c478bd9Sstevel@tonic-gate  *		force is not set
15657c478bd9Sstevel@tonic-gate  *		Call with cache_lock held
15667c478bd9Sstevel@tonic-gate  */
15677c478bd9Sstevel@tonic-gate static int
if_unplumb(ip_cache_t * node)15687c478bd9Sstevel@tonic-gate if_unplumb(ip_cache_t *node)
15697c478bd9Sstevel@tonic-gate {
15707c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
1571e11c3f44Smeem 	ip_pif_t *pif = node->ip_pif;
1572e11c3f44Smeem 	boolean_t ipv4 = B_FALSE;
1573e11c3f44Smeem 	boolean_t ipv6 = B_FALSE;
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource);
15767c478bd9Sstevel@tonic-gate 
1577e11c3f44Smeem 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
15787c478bd9Sstevel@tonic-gate 		if (lif->li_ifflags & IFF_IPV4) {
1579e11c3f44Smeem 			ipv4 = B_TRUE;
15807c478bd9Sstevel@tonic-gate 		} else if (lif->li_ifflags & IFF_IPV6) {
1581e11c3f44Smeem 			ipv6 = B_TRUE;
15827c478bd9Sstevel@tonic-gate 		} else {
15837c478bd9Sstevel@tonic-gate 			/* Unlikely case */
15847c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
1585d62bc4baSyz 			    "IP: Unplumb ignored (%s:%d)\n",
15867c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum);
15877c478bd9Sstevel@tonic-gate 		}
15887c478bd9Sstevel@tonic-gate 	}
15897c478bd9Sstevel@tonic-gate 
1590e11c3f44Smeem 	if (ipv4 && !ifconfig(pif->pi_ifname, "inet", "unplumb", B_FALSE)) {
1591e11c3f44Smeem 		rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
1592e11c3f44Smeem 		    pif->pi_ifname, strerror(errno));
1593e11c3f44Smeem 		return (-1);
15947c478bd9Sstevel@tonic-gate 	}
1595e11c3f44Smeem 
1596e11c3f44Smeem 	if (ipv6 && !ifconfig(pif->pi_ifname, "inet6", "unplumb", B_FALSE)) {
1597e11c3f44Smeem 		rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
1598e11c3f44Smeem 		    pif->pi_ifname, strerror(errno));
1599e11c3f44Smeem 		return (-1);
16007c478bd9Sstevel@tonic-gate 	}
1601e11c3f44Smeem 
16027c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n",
16037c478bd9Sstevel@tonic-gate 	    node->ip_resource);
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 	return (0);
16067c478bd9Sstevel@tonic-gate }
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate /*
16097c478bd9Sstevel@tonic-gate  * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface
16107c478bd9Sstevel@tonic-gate  *		instances and the logical interfaces in order, restoring
16117c478bd9Sstevel@tonic-gate  *		all ifconfig options
16127c478bd9Sstevel@tonic-gate  *		Call with cache_lock held
16137c478bd9Sstevel@tonic-gate  */
16147c478bd9Sstevel@tonic-gate static int
if_replumb(ip_cache_t * node)16157c478bd9Sstevel@tonic-gate if_replumb(ip_cache_t *node)
16167c478bd9Sstevel@tonic-gate {
16177c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
16187c478bd9Sstevel@tonic-gate 	ip_pif_t *pif;
16197c478bd9Sstevel@tonic-gate 	int i;
1620e11c3f44Smeem 	boolean_t success, ipmp;
1621e11c3f44Smeem 	const char *fstr;
1622e11c3f44Smeem 	char lifname[LIFNAMSIZ];
1623e11c3f44Smeem 	char buf[MAX_RECONFIG_SIZE];
1624e11c3f44Smeem 	int max_lifnum = 0;
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource);
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	/*
16297c478bd9Sstevel@tonic-gate 	 * Be extra careful about bringing up the interfaces in the
16307c478bd9Sstevel@tonic-gate 	 * correct order:
16317c478bd9Sstevel@tonic-gate 	 * - First plumb in the physical interface instances
16327c478bd9Sstevel@tonic-gate 	 * - modinsert the necessary modules@pos
16337c478bd9Sstevel@tonic-gate 	 * - Next, add the logical interfaces being careful about
16347c478bd9Sstevel@tonic-gate 	 *   the order, (follow the cached interface number li_ifnum order)
16357c478bd9Sstevel@tonic-gate 	 */
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	pif = node->ip_pif;
1638e11c3f44Smeem 	ipmp = (node->ip_pif->pi_grname[0] != '\0');
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	/*
16417c478bd9Sstevel@tonic-gate 	 * Make a first pass to plumb in physical interfaces and get a count
16427c478bd9Sstevel@tonic-gate 	 * of the max logical interfaces
16437c478bd9Sstevel@tonic-gate 	 */
1644e11c3f44Smeem 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1645e11c3f44Smeem 		max_lifnum = MAX(lif->li_ifnum, max_lifnum);
16467c478bd9Sstevel@tonic-gate 		if (lif->li_ifflags & IFF_IPV4) {
1647e11c3f44Smeem 			fstr = "inet";
16487c478bd9Sstevel@tonic-gate 		} else if (lif->li_ifflags & IFF_IPV6) {
1649e11c3f44Smeem 			fstr = "inet6";
16507c478bd9Sstevel@tonic-gate 		} else {
16517c478bd9Sstevel@tonic-gate 			/* Unlikely case */
16527c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
1653d62bc4baSyz 			    "IP: Re-plumb ignored (%s:%d)\n",
16547c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum);
16557c478bd9Sstevel@tonic-gate 			continue;
16567c478bd9Sstevel@tonic-gate 		}
16577c478bd9Sstevel@tonic-gate 
1658e11c3f44Smeem 		/* ignore logical interface instances */
1659e11c3f44Smeem 		if (lif->li_ifnum != 0)
1660e11c3f44Smeem 			continue;
1661e11c3f44Smeem 
1662e11c3f44Smeem 		if ((lif->li_ifflags & IFF_NOFAILOVER) || !ipmp) {
1663e11c3f44Smeem 			success = ifconfig("", "", lif->li_reconfig, B_FALSE);
1664e11c3f44Smeem 		} else {
1665e11c3f44Smeem 			(void) snprintf(buf, sizeof (buf), "plumb group %s",
1666e11c3f44Smeem 			    pif->pi_grname);
1667e11c3f44Smeem 			success = ifconfig(pif->pi_ifname, fstr, buf, B_FALSE);
1668e11c3f44Smeem 		}
1669e11c3f44Smeem 
1670e11c3f44Smeem 		if (!success) {
1671e11c3f44Smeem 			rcm_log_message(RCM_ERROR,
1672e11c3f44Smeem 			    _("IP: Cannot plumb (%s) %s\n"), pif->pi_ifname,
1673e11c3f44Smeem 			    strerror(errno));
1674e11c3f44Smeem 			return (-1);
1675e11c3f44Smeem 		}
1676e11c3f44Smeem 
1677e11c3f44Smeem 		/*
1678e11c3f44Smeem 		 * Restart DHCP if necessary.
1679e11c3f44Smeem 		 */
1680e11c3f44Smeem 		if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1681e11c3f44Smeem 		    !ifconfig(pif->pi_ifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1682e11c3f44Smeem 			rcm_log_message(RCM_ERROR, _("IP: Cannot start DHCP "
1683e11c3f44Smeem 			    "(%s) %s\n"), pif->pi_ifname, strerror(errno));
1684e11c3f44Smeem 			return (-1);
1685e11c3f44Smeem 		}
16867c478bd9Sstevel@tonic-gate 
1687e11c3f44Smeem 		rcm_log_message(RCM_TRACE2,
1688e11c3f44Smeem 		    "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt);
1689e11c3f44Smeem 		/* modinsert modules in order, ignore driver(last) */
1690e11c3f44Smeem 		for (i = 0; i < (lif->li_modcnt - 1); i++) {
16917c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE2,
1692e11c3f44Smeem 			    "IP: modinsert: Pos = %d Mod = %s\n",
1693e11c3f44Smeem 			    i, lif->li_modules[i]);
1694e11c3f44Smeem 			if (modop(pif->pi_ifname, lif->li_modules[i], i,
1695e11c3f44Smeem 			    MOD_INSERT) == -1) {
16967c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_ERROR,
1697e11c3f44Smeem 				    _("IP: modinsert error(%s)\n"),
1698e11c3f44Smeem 				    pif->pi_ifname);
16997c478bd9Sstevel@tonic-gate 				return (-1);
17007c478bd9Sstevel@tonic-gate 			}
17017c478bd9Sstevel@tonic-gate 		}
17027c478bd9Sstevel@tonic-gate 	}
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	/* Now, add all the logical interfaces in the correct order */
1705e11c3f44Smeem 	for (i = 1; i <= max_lifnum; i++) {
1706e11c3f44Smeem 		(void) snprintf(lifname, LIFNAMSIZ, "%s:%d", pif->pi_ifname, i);
1707e11c3f44Smeem 
17087c478bd9Sstevel@tonic-gate 		/* reset lif through every iteration */
1709e11c3f44Smeem 		for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1710e11c3f44Smeem 			/*
1711e11c3f44Smeem 			 * Process entries in order.  If the interface is
1712e11c3f44Smeem 			 * using IPMP, only process test addresses.
1713e11c3f44Smeem 			 */
1714e11c3f44Smeem 			if (lif->li_ifnum != i ||
1715e11c3f44Smeem 			    (ipmp && !(lif->li_ifflags & IFF_NOFAILOVER)))
1716e11c3f44Smeem 				continue;
1717e11c3f44Smeem 
1718e11c3f44Smeem 			if (!ifconfig("", "", lif->li_reconfig, B_FALSE)) {
1719e11c3f44Smeem 				rcm_log_message(RCM_ERROR,
1720e11c3f44Smeem 				    _("IP: Cannot addif (%s) %s\n"), lifname,
1721e11c3f44Smeem 				    strerror(errno));
1722e11c3f44Smeem 				return (-1);
1723e11c3f44Smeem 			}
1724e11c3f44Smeem 
1725e11c3f44Smeem 			/*
1726e11c3f44Smeem 			 * Restart DHCP if necessary.
1727e11c3f44Smeem 			 */
1728e11c3f44Smeem 			if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1729e11c3f44Smeem 			    !ifconfig(lifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1730e11c3f44Smeem 				rcm_log_message(RCM_ERROR,
1731e11c3f44Smeem 				    _("IP: Cannot start DHCP (%s) %s\n"),
1732e11c3f44Smeem 				    lifname, strerror(errno));
1733e11c3f44Smeem 				return (-1);
17347c478bd9Sstevel@tonic-gate 			}
17357c478bd9Sstevel@tonic-gate 		}
17367c478bd9Sstevel@tonic-gate 	}
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n",
17397c478bd9Sstevel@tonic-gate 	    node->ip_resource);
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 	return (0);
17427c478bd9Sstevel@tonic-gate }
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate /*
17457c478bd9Sstevel@tonic-gate  * clr_cfg_state() - Cleanup after errors in unplumb
17467c478bd9Sstevel@tonic-gate  */
17477c478bd9Sstevel@tonic-gate static void
clr_cfg_state(ip_pif_t * pif)17487c478bd9Sstevel@tonic-gate clr_cfg_state(ip_pif_t *pif)
17497c478bd9Sstevel@tonic-gate {
17507c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
17517c478bd9Sstevel@tonic-gate 	int i;
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	lif = pif->pi_lifs;
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	while (lif != NULL) {
17567c478bd9Sstevel@tonic-gate 		lif->li_modcnt = 0;
17577c478bd9Sstevel@tonic-gate 		free(lif->li_reconfig);
17587c478bd9Sstevel@tonic-gate 		lif->li_reconfig = NULL;
17597c478bd9Sstevel@tonic-gate 		for (i = 0; i < IP_MAX_MODS; i++) {
17607c478bd9Sstevel@tonic-gate 			free(lif->li_modules[i]);
17617c478bd9Sstevel@tonic-gate 			lif->li_modules[i] = NULL;
17627c478bd9Sstevel@tonic-gate 		}
17637c478bd9Sstevel@tonic-gate 		lif = lif->li_next;
17647c478bd9Sstevel@tonic-gate 	}
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate /*
1768e11c3f44Smeem  * Attempt to offline ip_cache_t `node'; returns an IPMP error code.
17697c478bd9Sstevel@tonic-gate  */
17707c478bd9Sstevel@tonic-gate static int
ip_ipmp_offline(ip_cache_t * node)1771e11c3f44Smeem ip_ipmp_offline(ip_cache_t *node)
17727c478bd9Sstevel@tonic-gate {
1773e11c3f44Smeem 	int retval;
1774e11c3f44Smeem 	ipmp_handle_t handle;
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n");
17777c478bd9Sstevel@tonic-gate 
1778e11c3f44Smeem 	if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
1779e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
1780e11c3f44Smeem 		    _("IP: cannot create ipmp handle: %s\n"),
1781e11c3f44Smeem 		    ipmp_errmsg(retval));
1782e11c3f44Smeem 		return (retval);
17837c478bd9Sstevel@tonic-gate 	}
17847c478bd9Sstevel@tonic-gate 
1785e11c3f44Smeem 	retval = ipmp_offline(handle, node->ip_pif->pi_ifname, node->ip_ifred);
1786e11c3f44Smeem 	if (retval != IPMP_SUCCESS) {
1787e11c3f44Smeem 		rcm_log_message(RCM_ERROR, _("IP: ipmp_offline error: %s\n"),
1788e11c3f44Smeem 		    ipmp_errmsg(retval));
1789e11c3f44Smeem 	} else {
1790e11c3f44Smeem 		rcm_log_message(RCM_TRACE1, "IP: ipmp_offline success\n");
17917c478bd9Sstevel@tonic-gate 	}
17927c478bd9Sstevel@tonic-gate 
1793e11c3f44Smeem 	ipmp_close(handle);
1794e11c3f44Smeem 	return (retval);
17957c478bd9Sstevel@tonic-gate }
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate /*
1798e11c3f44Smeem  * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code.
17997c478bd9Sstevel@tonic-gate  */
18007c478bd9Sstevel@tonic-gate static int
ip_ipmp_undo_offline(ip_cache_t * node)18017c478bd9Sstevel@tonic-gate ip_ipmp_undo_offline(ip_cache_t *node)
18027c478bd9Sstevel@tonic-gate {
1803e11c3f44Smeem 	int retval;
1804e11c3f44Smeem 	ipmp_handle_t handle;
18057c478bd9Sstevel@tonic-gate 
1806e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_undo_offline\n");
18077c478bd9Sstevel@tonic-gate 
1808e11c3f44Smeem 	if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
18097c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
1810e11c3f44Smeem 		    _("IP: cannot create ipmp handle: %s\n"),
1811e11c3f44Smeem 		    ipmp_errmsg(retval));
1812e11c3f44Smeem 		return (retval);
18137c478bd9Sstevel@tonic-gate 	}
18147c478bd9Sstevel@tonic-gate 
1815e11c3f44Smeem 	retval = ipmp_undo_offline(handle, node->ip_pif->pi_ifname);
1816e11c3f44Smeem 	if (retval != IPMP_SUCCESS) {
1817e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
1818e11c3f44Smeem 		    _("IP: ipmp_undo_offline error: %s\n"),
1819e11c3f44Smeem 		    ipmp_errmsg(retval));
1820e11c3f44Smeem 	} else {
1821e11c3f44Smeem 		rcm_log_message(RCM_TRACE1, "IP: ipmp_undo_offline success\n");
1822e11c3f44Smeem 	}
1823e11c3f44Smeem 
1824e11c3f44Smeem 	ipmp_close(handle);
1825e11c3f44Smeem 	return (retval);
18267c478bd9Sstevel@tonic-gate }
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate /*
1829d62bc4baSyz  * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a
1830d62bc4baSyz  * dynamically allocated string containing the associated link resource
1831d62bc4baSyz  * name ("SUNW_datalink/<linkid>").
18327c478bd9Sstevel@tonic-gate  */
18337c478bd9Sstevel@tonic-gate static char *
get_link_resource(const char * link)1834d62bc4baSyz get_link_resource(const char *link)
18357c478bd9Sstevel@tonic-gate {
1836d62bc4baSyz 	char		errmsg[DLADM_STRSIZE];
1837d62bc4baSyz 	datalink_id_t	linkid;
1838d62bc4baSyz 	uint32_t	flags;
1839d62bc4baSyz 	char		*resource;
1840d62bc4baSyz 	dladm_status_t	status;
18417c478bd9Sstevel@tonic-gate 
1842e11c3f44Smeem 	status = dladm_name2info(dld_handle, link, &linkid, &flags, NULL, NULL);
1843e11c3f44Smeem 	if (status != DLADM_STATUS_OK)
1844d62bc4baSyz 		goto fail;
18457c478bd9Sstevel@tonic-gate 
1846d62bc4baSyz 	if (!(flags & DLADM_OPT_ACTIVE)) {
1847d62bc4baSyz 		status = DLADM_STATUS_FAILED;
1848d62bc4baSyz 		goto fail;
1849d62bc4baSyz 	}
1850d62bc4baSyz 
1851d62bc4baSyz 	resource = malloc(RCM_LINK_RESOURCE_MAX);
1852d62bc4baSyz 	if (resource == NULL) {
1853595aa6e4Smeem 		rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"),
1854d62bc4baSyz 		    strerror(errno), link);
18557c478bd9Sstevel@tonic-gate 		return (NULL);
18567c478bd9Sstevel@tonic-gate 	}
18577c478bd9Sstevel@tonic-gate 
1858d62bc4baSyz 	(void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u",
1859d62bc4baSyz 	    RCM_LINK_PREFIX, linkid);
18607c478bd9Sstevel@tonic-gate 
1861d62bc4baSyz 	return (resource);
1862d62bc4baSyz 
1863d62bc4baSyz fail:
1864d62bc4baSyz 	rcm_log_message(RCM_ERROR,
1865d62bc4baSyz 	    _("IP: get_link_resource for %s error(%s)\n"),
1866d62bc4baSyz 	    link, dladm_status2str(status, errmsg));
1867d62bc4baSyz 	return (NULL);
18687c478bd9Sstevel@tonic-gate }
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate /*
1871e11c3f44Smeem  * modop() - Remove/insert a module
18727c478bd9Sstevel@tonic-gate  */
1873e11c3f44Smeem static int
modop(char * name,char * arg,int pos,char op)1874e11c3f44Smeem modop(char *name, char *arg, int pos, char op)
18757c478bd9Sstevel@tonic-gate {
1876e11c3f44Smeem 	char syscmd[LIFNAMSIZ+MAXPATHLEN];	/* must be big enough */
18777c478bd9Sstevel@tonic-gate 
1878e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name);
1879e11c3f44Smeem 
1880e11c3f44Smeem 	/* Nothing to do with "ip", "arp" */
1881e11c3f44Smeem 	if ((arg == NULL) || (strcmp(arg, "") == 0) ||
1882e11c3f44Smeem 	    STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) {
1883e11c3f44Smeem 		rcm_log_message(RCM_TRACE1, "IP: modop success\n");
1884e11c3f44Smeem 		return (0);
1885e11c3f44Smeem 	}
1886e11c3f44Smeem 
1887e11c3f44Smeem 	if (op == MOD_CHECK) {
1888e11c3f44Smeem 		/*
1889e11c3f44Smeem 		 * No known good modules (yet) apart from ip and arp
1890e11c3f44Smeem 		 * which are handled above
1891e11c3f44Smeem 		 */
1892e11c3f44Smeem 		return (-1);
1893e11c3f44Smeem 	}
1894e11c3f44Smeem 
1895e11c3f44Smeem 	if (op == MOD_REMOVE) {
1896e11c3f44Smeem 		(void) snprintf(syscmd, sizeof (syscmd),
1897e11c3f44Smeem 		    "%s %s modremove %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
1898e11c3f44Smeem 	} else if (op == MOD_INSERT) {
1899e11c3f44Smeem 		(void) snprintf(syscmd, sizeof (syscmd),
1900e11c3f44Smeem 		    "%s %s modinsert %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
1901e11c3f44Smeem 	} else {
1902e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
1903e11c3f44Smeem 		    _("IP: modop(%s): unknown operation\n"), name);
1904e11c3f44Smeem 		return (-1);
1905e11c3f44Smeem 	}
1906e11c3f44Smeem 
1907e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd);
1908e11c3f44Smeem 	if (rcm_exec_cmd(syscmd) == -1) {
1909e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
1910e11c3f44Smeem 		    _("IP: modop(%s): %s\n"), name, strerror(errno));
1911e11c3f44Smeem 		return (-1);
19127c478bd9Sstevel@tonic-gate 	}
1913e11c3f44Smeem 
1914e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: modop success\n");
19157c478bd9Sstevel@tonic-gate 	return (0);
19167c478bd9Sstevel@tonic-gate }
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate /*
1919e11c3f44Smeem  * get_modlist() - return a list of pushed mid-stream modules
1920e11c3f44Smeem  *		 Required memory is malloced to construct the list,
1921e11c3f44Smeem  *		 Caller must free this memory list
1922e11c3f44Smeem  *		 Call with cache_lock held
19237c478bd9Sstevel@tonic-gate  */
19247c478bd9Sstevel@tonic-gate static int
get_modlist(char * name,ip_lif_t * lif)1925e11c3f44Smeem get_modlist(char *name, ip_lif_t *lif)
19267c478bd9Sstevel@tonic-gate {
1927e11c3f44Smeem 	int mux_fd;
1928e11c3f44Smeem 	int muxid_fd;
1929e11c3f44Smeem 	int fd;
19307c478bd9Sstevel@tonic-gate 	int i;
1931e11c3f44Smeem 	int num_mods;
1932e11c3f44Smeem 	struct lifreq lifr;
1933e11c3f44Smeem 	struct str_list strlist = { 0 };
19347c478bd9Sstevel@tonic-gate 
1935e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name);
19367c478bd9Sstevel@tonic-gate 
1937e11c3f44Smeem 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1938e11c3f44Smeem 	lifr.lifr_flags = lif->li_ifflags;
1939e11c3f44Smeem 	if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) {
1940e11c3f44Smeem 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name);
1941e11c3f44Smeem 		return (-1);
1942e11c3f44Smeem 	}
19437c478bd9Sstevel@tonic-gate 
1944e11c3f44Smeem 	if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) {
1945e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
1946e11c3f44Smeem 		    _("IP: get_modlist(%s): I_LIST(%s) \n"),
1947e11c3f44Smeem 		    name, strerror(errno));
1948e11c3f44Smeem 		goto fail;
1949e11c3f44Smeem 	}
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 	strlist.sl_nmods = num_mods;
19527c478bd9Sstevel@tonic-gate 	strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods);
19537c478bd9Sstevel@tonic-gate 	if (strlist.sl_modlist == NULL) {
19547c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"),
19557c478bd9Sstevel@tonic-gate 		    name, strerror(errno));
1956e11c3f44Smeem 		goto fail;
19577c478bd9Sstevel@tonic-gate 	}
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
19607c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
19617c478bd9Sstevel@tonic-gate 		    _("IP: get_modlist(%s): I_LIST error: %s\n"),
19627c478bd9Sstevel@tonic-gate 		    name, strerror(errno));
1963e11c3f44Smeem 		goto fail;
19647c478bd9Sstevel@tonic-gate 	}
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 	for (i = 0; i < strlist.sl_nmods; i++) {
1967e11c3f44Smeem 		lif->li_modules[i] = strdup(strlist.sl_modlist[i].l_name);
19687c478bd9Sstevel@tonic-gate 		if (lif->li_modules[i] == NULL) {
19697c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
19707c478bd9Sstevel@tonic-gate 			    _("IP: get_modlist(%s): %s\n"),
19717c478bd9Sstevel@tonic-gate 			    name, strerror(errno));
1972e11c3f44Smeem 			while (i > 0)
1973e11c3f44Smeem 				free(lif->li_modules[--i]);
1974e11c3f44Smeem 			goto fail;
19757c478bd9Sstevel@tonic-gate 		}
19767c478bd9Sstevel@tonic-gate 	}
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	lif->li_modcnt = strlist.sl_nmods;
19797c478bd9Sstevel@tonic-gate 	free(strlist.sl_modlist);
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name);
1982fc80c0dfSnordmark 	return (ip_plink(mux_fd, muxid_fd, fd, &lifr));
1983e11c3f44Smeem fail:
1984e11c3f44Smeem 	free(strlist.sl_modlist);
1985e11c3f44Smeem 	(void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
1986e11c3f44Smeem 	return (-1);
19877c478bd9Sstevel@tonic-gate }
19887c478bd9Sstevel@tonic-gate 
19897c478bd9Sstevel@tonic-gate /*
19907c478bd9Sstevel@tonic-gate  * ip_domux2fd() - Helper function for mod*() functions
19917c478bd9Sstevel@tonic-gate  *		 Stolen from ifconfig.c
19927c478bd9Sstevel@tonic-gate  */
19937c478bd9Sstevel@tonic-gate static int
ip_domux2fd(int * mux_fd,int * muxid_fdp,int * fd,struct lifreq * lifr)1994fc80c0dfSnordmark ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr)
19957c478bd9Sstevel@tonic-gate {
1996fc80c0dfSnordmark 	int muxid_fd;
19977c478bd9Sstevel@tonic-gate 	char	*udp_dev_name;
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 	if (lifr->lifr_flags & IFF_IPV6) {
2000fc80c0dfSnordmark 		udp_dev_name  = UDP6_DEV_NAME;
20017c478bd9Sstevel@tonic-gate 	} else {
2002fc80c0dfSnordmark 		udp_dev_name  = UDP_DEV_NAME;
20037c478bd9Sstevel@tonic-gate 	}
20047c478bd9Sstevel@tonic-gate 
2005fc80c0dfSnordmark 	if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) {
20067c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2007fc80c0dfSnordmark 		    udp_dev_name, strerror(errno));
20087c478bd9Sstevel@tonic-gate 		return (-1);
20097c478bd9Sstevel@tonic-gate 	}
2010fc80c0dfSnordmark 	if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) {
20117c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
20127c478bd9Sstevel@tonic-gate 		    udp_dev_name, strerror(errno));
2013fc80c0dfSnordmark 		(void) close(muxid_fd);
20147c478bd9Sstevel@tonic-gate 		return (-1);
20157c478bd9Sstevel@tonic-gate 	}
2016fc80c0dfSnordmark 	if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) {
20177c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
20187c478bd9Sstevel@tonic-gate 		    _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"),
2019fc80c0dfSnordmark 		    udp_dev_name, strerror(errno));
2020fc80c0dfSnordmark 		(void) close(*mux_fd);
2021fc80c0dfSnordmark 		(void) close(muxid_fd);
20227c478bd9Sstevel@tonic-gate 		return (-1);
20237c478bd9Sstevel@tonic-gate 	}
20247c478bd9Sstevel@tonic-gate 
20257c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2,
20267c478bd9Sstevel@tonic-gate 	    "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n",
20277c478bd9Sstevel@tonic-gate 	    lifr->lifr_arp_muxid, lifr->lifr_ip_muxid);
20287c478bd9Sstevel@tonic-gate 
2029fc80c0dfSnordmark 	if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) {
20307c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
20317c478bd9Sstevel@tonic-gate 		    _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"),
20327c478bd9Sstevel@tonic-gate 		    udp_dev_name, strerror(errno));
2033fc80c0dfSnordmark 		(void) close(*mux_fd);
2034fc80c0dfSnordmark 		(void) close(muxid_fd);
20357c478bd9Sstevel@tonic-gate 		return (-1);
20367c478bd9Sstevel@tonic-gate 	}
2037fc80c0dfSnordmark 	if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) {
20387c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
20397c478bd9Sstevel@tonic-gate 		    _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"),
20407c478bd9Sstevel@tonic-gate 		    udp_dev_name, strerror(errno));
2041fc80c0dfSnordmark 		(void) close(*mux_fd);
2042fc80c0dfSnordmark 		(void) close(muxid_fd);
20437c478bd9Sstevel@tonic-gate 		return (-1);
20447c478bd9Sstevel@tonic-gate 	}
20457c478bd9Sstevel@tonic-gate 
2046fc80c0dfSnordmark 	/* Note: mux_fd and muxid_fd are closed in ip_plink below */
2047fc80c0dfSnordmark 	*muxid_fdp = muxid_fd;
20487c478bd9Sstevel@tonic-gate 	return (0);
20497c478bd9Sstevel@tonic-gate }
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate /*
20527c478bd9Sstevel@tonic-gate  * ip_plink() - Helper function for mod*() functions.
20537c478bd9Sstevel@tonic-gate  *	      Stolen from ifconfig.c
20547c478bd9Sstevel@tonic-gate  */
20557c478bd9Sstevel@tonic-gate static int
ip_plink(int mux_fd,int muxid_fd,int fd,struct lifreq * lifr)2056fc80c0dfSnordmark ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr)
20577c478bd9Sstevel@tonic-gate {
20587c478bd9Sstevel@tonic-gate 	int mux_id;
20597c478bd9Sstevel@tonic-gate 
2060fc80c0dfSnordmark 	if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) {
20617c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"),
20627c478bd9Sstevel@tonic-gate 		    UDP_DEV_NAME, strerror(errno));
2063fc80c0dfSnordmark 		(void) close(mux_fd);
2064fc80c0dfSnordmark 		(void) close(muxid_fd);
20657c478bd9Sstevel@tonic-gate 		(void) close(fd);
20667c478bd9Sstevel@tonic-gate 		return (-1);
20677c478bd9Sstevel@tonic-gate 	}
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	lifr->lifr_ip_muxid = mux_id;
2070fc80c0dfSnordmark 	if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) {
20717c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
20727c478bd9Sstevel@tonic-gate 		    _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"),
20737c478bd9Sstevel@tonic-gate 		    UDP_DEV_NAME, strerror(errno));
2074fc80c0dfSnordmark 		(void) close(mux_fd);
2075fc80c0dfSnordmark 		(void) close(muxid_fd);
20767c478bd9Sstevel@tonic-gate 		(void) close(fd);
20777c478bd9Sstevel@tonic-gate 		return (-1);
20787c478bd9Sstevel@tonic-gate 	}
20797c478bd9Sstevel@tonic-gate 
2080fc80c0dfSnordmark 	(void) close(mux_fd);
2081fc80c0dfSnordmark 	(void) close(muxid_fd);
20827c478bd9Sstevel@tonic-gate 	(void) close(fd);
20837c478bd9Sstevel@tonic-gate 	return (0);
20847c478bd9Sstevel@tonic-gate }
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate /*
20877c478bd9Sstevel@tonic-gate  * ip_onlinelist()
20887c478bd9Sstevel@tonic-gate  *
20897c478bd9Sstevel@tonic-gate  *	Notify online to IP address consumers.
20907c478bd9Sstevel@tonic-gate  */
2091e11c3f44Smeem /*ARGSUSED*/
20927c478bd9Sstevel@tonic-gate static int
ip_onlinelist(rcm_handle_t * hd,ip_cache_t * node,char ** errorp,uint_t flags,rcm_info_t ** depend_info)20937c478bd9Sstevel@tonic-gate ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
209446fbc806SToomas Soome     rcm_info_t **depend_info)
20957c478bd9Sstevel@tonic-gate {
20967c478bd9Sstevel@tonic-gate 	char **addrlist;
20977c478bd9Sstevel@tonic-gate 	int ret = RCM_SUCCESS;
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n");
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	addrlist = ip_get_addrlist(node);
21027c478bd9Sstevel@tonic-gate 	if (addrlist == NULL || addrlist[0] == NULL) {
21037c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n");
21047c478bd9Sstevel@tonic-gate 		ip_free_addrlist(addrlist);
21057c478bd9Sstevel@tonic-gate 		return (ret);
21067c478bd9Sstevel@tonic-gate 	}
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 	ret = rcm_notify_online_list(hd, addrlist, 0, depend_info);
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate 	ip_free_addrlist(addrlist);
21117c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n");
21127c478bd9Sstevel@tonic-gate 	return (ret);
21137c478bd9Sstevel@tonic-gate }
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate /*
21167c478bd9Sstevel@tonic-gate  * ip_offlinelist()
21177c478bd9Sstevel@tonic-gate  *
21187c478bd9Sstevel@tonic-gate  *	Offline IP address consumers.
21197c478bd9Sstevel@tonic-gate  */
2120e11c3f44Smeem /*ARGSUSED*/
21217c478bd9Sstevel@tonic-gate static int
ip_offlinelist(rcm_handle_t * hd,ip_cache_t * node,char ** errorp,uint_t flags,rcm_info_t ** depend_info)21227c478bd9Sstevel@tonic-gate ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
212346fbc806SToomas Soome     rcm_info_t **depend_info)
21247c478bd9Sstevel@tonic-gate {
21257c478bd9Sstevel@tonic-gate 	char **addrlist;
21267c478bd9Sstevel@tonic-gate 	int ret = RCM_SUCCESS;
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n");
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	addrlist = ip_get_addrlist(node);
21317c478bd9Sstevel@tonic-gate 	if (addrlist == NULL || addrlist[0] == NULL) {
21327c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n");
21337c478bd9Sstevel@tonic-gate 		ip_free_addrlist(addrlist);
21347c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
21357c478bd9Sstevel@tonic-gate 	}
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 	if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info))
21387c478bd9Sstevel@tonic-gate 	    != RCM_SUCCESS) {
21397c478bd9Sstevel@tonic-gate 		if (ret == RCM_FAILURE)
21407c478bd9Sstevel@tonic-gate 			(void) rcm_notify_online_list(hd, addrlist, 0, NULL);
21417c478bd9Sstevel@tonic-gate 
21427c478bd9Sstevel@tonic-gate 		ret = RCM_FAILURE;
21437c478bd9Sstevel@tonic-gate 	}
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate 	ip_free_addrlist(addrlist);
21467c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n");
21477c478bd9Sstevel@tonic-gate 	return (ret);
21487c478bd9Sstevel@tonic-gate }
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate /*
2151e11c3f44Smeem  * ip_get_addrlist() -	Get the list of IP addresses on this interface (node);
2152e11c3f44Smeem  *			This routine malloc()s required memory for the list.
2153e11c3f44Smeem  *			Returns the list on success, NULL on failure.
21547c478bd9Sstevel@tonic-gate  *			Call with cache_lock held.
21557c478bd9Sstevel@tonic-gate  */
21567c478bd9Sstevel@tonic-gate static char **
ip_get_addrlist(ip_cache_t * node)21577c478bd9Sstevel@tonic-gate ip_get_addrlist(ip_cache_t *node)
21587c478bd9Sstevel@tonic-gate {
21597c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
21607c478bd9Sstevel@tonic-gate 	char **addrlist = NULL;
2161e11c3f44Smeem 	int i, numifs;
2162e11c3f44Smeem 	size_t addrlistsize;
21637c478bd9Sstevel@tonic-gate 	char addrstr[INET6_ADDRSTRLEN];
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n",
21667c478bd9Sstevel@tonic-gate 	    node->ip_resource);
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	numifs = 0;
21697c478bd9Sstevel@tonic-gate 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
21707c478bd9Sstevel@tonic-gate 		numifs++;
21717c478bd9Sstevel@tonic-gate 	}
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	/*
21747c478bd9Sstevel@tonic-gate 	 * Allocate space for resource names list; add 1 and use calloc()
21757c478bd9Sstevel@tonic-gate 	 * so that the list is NULL-terminated.
21767c478bd9Sstevel@tonic-gate 	 */
21777c478bd9Sstevel@tonic-gate 	if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) {
21787c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
21797c478bd9Sstevel@tonic-gate 		    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
21807c478bd9Sstevel@tonic-gate 		    node->ip_resource, strerror(errno));
21817c478bd9Sstevel@tonic-gate 		return (NULL);
21827c478bd9Sstevel@tonic-gate 	}
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate 	for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL;
21857c478bd9Sstevel@tonic-gate 	    lif = lif->li_next, i++) {
21867c478bd9Sstevel@tonic-gate 
2187e11c3f44Smeem 		if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) {
21887c478bd9Sstevel@tonic-gate 			ip_free_addrlist(addrlist);
21897c478bd9Sstevel@tonic-gate 			return (NULL);
21907c478bd9Sstevel@tonic-gate 		}
21917c478bd9Sstevel@tonic-gate 
2192e11c3f44Smeem 		addrlistsize = strlen(addrstr) + sizeof (RCM_STR_SUNW_IP);
2193e11c3f44Smeem 		if ((addrlist[i] = malloc(addrlistsize)) == NULL) {
21947c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
21957c478bd9Sstevel@tonic-gate 			    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
21967c478bd9Sstevel@tonic-gate 			    node->ip_resource, strerror(errno));
21977c478bd9Sstevel@tonic-gate 			ip_free_addrlist(addrlist);
21987c478bd9Sstevel@tonic-gate 			return (NULL);
21997c478bd9Sstevel@tonic-gate 		}
2200e11c3f44Smeem 		(void) snprintf(addrlist[i], addrlistsize, "%s%s",
2201e11c3f44Smeem 		    RCM_STR_SUNW_IP, addrstr);
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]);
22047c478bd9Sstevel@tonic-gate 	}
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n",
22077c478bd9Sstevel@tonic-gate 	    node->ip_resource);
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	return (addrlist);
22107c478bd9Sstevel@tonic-gate }
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate static void
ip_free_addrlist(char ** addrlist)22137c478bd9Sstevel@tonic-gate ip_free_addrlist(char **addrlist)
22147c478bd9Sstevel@tonic-gate {
22157c478bd9Sstevel@tonic-gate 	int i;
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 	if (addrlist == NULL)
22187c478bd9Sstevel@tonic-gate 		return;
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	for (i = 0; addrlist[i] != NULL; i++)
22217c478bd9Sstevel@tonic-gate 		free(addrlist[i]);
22227c478bd9Sstevel@tonic-gate 	free(addrlist);
22237c478bd9Sstevel@tonic-gate }
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate /*
22267c478bd9Sstevel@tonic-gate  * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
22277c478bd9Sstevel@tonic-gate  */
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate static void
ip_consumer_notify(rcm_handle_t * hd,datalink_id_t linkid,char ** errorp,uint_t flags,rcm_info_t ** depend_info)2230d62bc4baSyz ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
2231d62bc4baSyz     uint_t flags, rcm_info_t **depend_info)
22327c478bd9Sstevel@tonic-gate {
2233d62bc4baSyz 	char cached_name[RCM_LINK_RESOURCE_MAX];
22347c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
22357c478bd9Sstevel@tonic-gate 
2236d62bc4baSyz 	assert(linkid != DATALINK_INVALID_LINKID);
22377c478bd9Sstevel@tonic-gate 
2238d62bc4baSyz 	rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid);
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 	/* Check for the interface in the cache */
2241d62bc4baSyz 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2242d62bc4baSyz 	    RCM_LINK_PREFIX, linkid);
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
22457c478bd9Sstevel@tonic-gate 	if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) {
2246d62bc4baSyz 		rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"),
2247d62bc4baSyz 		    linkid);
22487c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
22497c478bd9Sstevel@tonic-gate 		return;
22507c478bd9Sstevel@tonic-gate 	}
22517c478bd9Sstevel@tonic-gate 	/*
2252e11c3f44Smeem 	 * Inform anonymous consumers about IP addresses being onlined.
22537c478bd9Sstevel@tonic-gate 	 */
22547c478bd9Sstevel@tonic-gate 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n");
22597c478bd9Sstevel@tonic-gate }
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate /*
22626e91bba0SGirish Moodalbail  * Gets the interface name for the given linkid. Returns -1 if there is
22636e91bba0SGirish Moodalbail  * any error. It fills in the interface name in `ifinst' if the interface
22646e91bba0SGirish Moodalbail  * is not already configured. Otherwise, it puts a null string in `ifinst'.
22657c478bd9Sstevel@tonic-gate  */
22667c478bd9Sstevel@tonic-gate static int
if_configure_get_linkid(datalink_id_t linkid,char * ifinst,size_t len)22676e91bba0SGirish Moodalbail if_configure_get_linkid(datalink_id_t linkid, char *ifinst, size_t len)
22687c478bd9Sstevel@tonic-gate {
2269d62bc4baSyz 	char cached_name[RCM_LINK_RESOURCE_MAX];
22707c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
22717c478bd9Sstevel@tonic-gate 
22727c478bd9Sstevel@tonic-gate 	/* Check for the interface in the cache */
2273d62bc4baSyz 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2274d62bc4baSyz 	    RCM_LINK_PREFIX, linkid);
22757c478bd9Sstevel@tonic-gate 
2276e11c3f44Smeem 	/* Check if the interface is new or was not previously offlined */
22777c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
22787c478bd9Sstevel@tonic-gate 	if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) &&
22797c478bd9Sstevel@tonic-gate 	    (!(node->ip_cachestate & CACHE_IF_OFFLINED))) {
22807c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1,
2281d62bc4baSyz 		    _("IP: Skipping configured interface(%u)\n"), linkid);
22827c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
22836e91bba0SGirish Moodalbail 		*ifinst = '\0';
22847c478bd9Sstevel@tonic-gate 		return (0);
22857c478bd9Sstevel@tonic-gate 	}
22867c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
22877c478bd9Sstevel@tonic-gate 
22884ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, NULL, ifinst,
22896e91bba0SGirish Moodalbail 	    len) != DLADM_STATUS_OK) {
2290d62bc4baSyz 		rcm_log_message(RCM_ERROR,
2291d62bc4baSyz 		    _("IP: get %u link name failed\n"), linkid);
2292d62bc4baSyz 		return (-1);
2293d62bc4baSyz 	}
22946e91bba0SGirish Moodalbail 	return (0);
22956e91bba0SGirish Moodalbail }
22966e91bba0SGirish Moodalbail 
22976e91bba0SGirish Moodalbail /*
22986e91bba0SGirish Moodalbail  * if_configure_hostname() - Configure a physical interface after attach
22996e91bba0SGirish Moodalbail  * based on the information in /etc/hostname.*
23006e91bba0SGirish Moodalbail  */
23016e91bba0SGirish Moodalbail static int
if_configure_hostname(datalink_id_t linkid)23026e91bba0SGirish Moodalbail if_configure_hostname(datalink_id_t linkid)
23036e91bba0SGirish Moodalbail {
23046e91bba0SGirish Moodalbail 	FILE *hostfp, *host6fp;
23056e91bba0SGirish Moodalbail 	boolean_t ipmp = B_FALSE;
23066e91bba0SGirish Moodalbail 	char ifinst[MAXLINKNAMELEN];
23076e91bba0SGirish Moodalbail 	char cfgfile[MAXPATHLEN];
23086e91bba0SGirish Moodalbail 
23096e91bba0SGirish Moodalbail 	assert(linkid != DATALINK_INVALID_LINKID);
23106e91bba0SGirish Moodalbail 	rcm_log_message(RCM_TRACE1, _("IP: if_configure_hostname(%u)\n"),
23116e91bba0SGirish Moodalbail 	    linkid);
23126e91bba0SGirish Moodalbail 
23136e91bba0SGirish Moodalbail 	if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
23146e91bba0SGirish Moodalbail 		return (-1);
23156e91bba0SGirish Moodalbail 
23166e91bba0SGirish Moodalbail 	/* Check if the interface is already configured. */
23176e91bba0SGirish Moodalbail 	if (ifinst[0] == '\0')
23186e91bba0SGirish Moodalbail 		return (0);
2319d62bc4baSyz 
2320e11c3f44Smeem 	/*
2321e11c3f44Smeem 	 * Scan the IPv4 and IPv6 hostname files to see if (a) they exist
2322e11c3f44Smeem 	 * and (b) if either one places the interface into an IPMP group.
2323e11c3f44Smeem 	 */
2324e11c3f44Smeem 	(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifinst);
23257c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2326e11c3f44Smeem 	if ((hostfp = fopen(cfgfile, "r")) != NULL) {
2327e11c3f44Smeem 		if (isgrouped(cfgfile))
2328e11c3f44Smeem 			ipmp = B_TRUE;
23297c478bd9Sstevel@tonic-gate 	}
23307c478bd9Sstevel@tonic-gate 
2331e11c3f44Smeem 	(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifinst);
23327c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2333e11c3f44Smeem 	if ((host6fp = fopen(cfgfile, "r")) != NULL) {
2334e11c3f44Smeem 		if (!ipmp && isgrouped(cfgfile))
2335e11c3f44Smeem 			ipmp = B_TRUE;
23367c478bd9Sstevel@tonic-gate 	}
23377c478bd9Sstevel@tonic-gate 
2338e11c3f44Smeem 	/*
2339e11c3f44Smeem 	 * Configure the interface according to its hostname files.
2340e11c3f44Smeem 	 */
2341e11c3f44Smeem 	if (hostfp != NULL &&
2342e11c3f44Smeem 	    if_config_inst(ifinst, hostfp, AF_INET, ipmp) == -1) {
2343e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
2344e11c3f44Smeem 		    _("IP: IPv4 Post-attach failed (%s)\n"), ifinst);
2345e11c3f44Smeem 		goto fail;
23467c478bd9Sstevel@tonic-gate 	}
23477c478bd9Sstevel@tonic-gate 
2348e11c3f44Smeem 	if (host6fp != NULL &&
2349e11c3f44Smeem 	    if_config_inst(ifinst, host6fp, AF_INET6, ipmp) == -1) {
2350e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
2351e11c3f44Smeem 		    _("IP: IPv6 Post-attach failed (%s)\n"), ifinst);
2352e11c3f44Smeem 		goto fail;
23537c478bd9Sstevel@tonic-gate 	}
23547c478bd9Sstevel@tonic-gate 
2355e11c3f44Smeem 	(void) fclose(hostfp);
2356e11c3f44Smeem 	(void) fclose(host6fp);
23576e91bba0SGirish Moodalbail 	rcm_log_message(RCM_TRACE1, "IP: if_configure_hostname(%s) success\n",
23586e91bba0SGirish Moodalbail 	    ifinst);
23597c478bd9Sstevel@tonic-gate 	return (0);
2360e11c3f44Smeem fail:
2361e11c3f44Smeem 	(void) fclose(hostfp);
2362e11c3f44Smeem 	(void) fclose(host6fp);
2363e11c3f44Smeem 	return (-1);
23647c478bd9Sstevel@tonic-gate }
23657c478bd9Sstevel@tonic-gate 
23666e91bba0SGirish Moodalbail /*
23676e91bba0SGirish Moodalbail  * if_configure_ipadm() - Configure a physical interface after attach
23686e91bba0SGirish Moodalbail  * Queries libipadm for persistent configuration information and then
23696e91bba0SGirish Moodalbail  * resurrects that persistent configuration.
23706e91bba0SGirish Moodalbail  */
23716e91bba0SGirish Moodalbail static int
if_configure_ipadm(datalink_id_t linkid)23726e91bba0SGirish Moodalbail if_configure_ipadm(datalink_id_t linkid)
23736e91bba0SGirish Moodalbail {
23746e91bba0SGirish Moodalbail 	char ifinst[MAXLINKNAMELEN];
23756e91bba0SGirish Moodalbail 	boolean_t found;
2376a73be61aSHans Rosenfeld 	ipadm_if_info_t *ifinfo, *ptr;
23776e91bba0SGirish Moodalbail 	ipadm_status_t status;
23786e91bba0SGirish Moodalbail 
23796e91bba0SGirish Moodalbail 	assert(linkid != DATALINK_INVALID_LINKID);
23806e91bba0SGirish Moodalbail 	rcm_log_message(RCM_TRACE1, _("IP: if_configure_ipadm(%u)\n"),
23816e91bba0SGirish Moodalbail 	    linkid);
23826e91bba0SGirish Moodalbail 
23836e91bba0SGirish Moodalbail 	if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
23846e91bba0SGirish Moodalbail 		return (-1);
23856e91bba0SGirish Moodalbail 
23866e91bba0SGirish Moodalbail 	/* Check if the interface is already configured. */
23876e91bba0SGirish Moodalbail 	if (ifinst[0] == '\0')
23886e91bba0SGirish Moodalbail 		return (0);
23896e91bba0SGirish Moodalbail 
23906e91bba0SGirish Moodalbail 	status = ipadm_if_info(ip_handle, ifinst, &ifinfo, 0, LIFC_UNDER_IPMP);
23916e91bba0SGirish Moodalbail 	if (status == IPADM_ENXIO)
23926e91bba0SGirish Moodalbail 		goto done;
23936e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS) {
23946e91bba0SGirish Moodalbail 		rcm_log_message(RCM_ERROR,
23956e91bba0SGirish Moodalbail 		    _("IP: IPv4 Post-attach failed (%s) Error %s\n"),
23966e91bba0SGirish Moodalbail 		    ifinst, ipadm_status2str(status));
23976e91bba0SGirish Moodalbail 		goto fail;
23986e91bba0SGirish Moodalbail 	}
23996e91bba0SGirish Moodalbail 	if (ifinfo != NULL) {
24006e91bba0SGirish Moodalbail 		found = B_FALSE;
2401a73be61aSHans Rosenfeld 		for (ptr = ifinfo; ptr != NULL; ptr = ptr->ifi_next) {
2402a73be61aSHans Rosenfeld 			if (strncmp(ptr->ifi_name, ifinst,
24036e91bba0SGirish Moodalbail 			    sizeof (ifinst)) == 0) {
24046e91bba0SGirish Moodalbail 				found = B_TRUE;
24056e91bba0SGirish Moodalbail 				break;
24066e91bba0SGirish Moodalbail 			}
24076e91bba0SGirish Moodalbail 		}
2408ed1e9379SHans Rosenfeld 		ipadm_free_if_info(ifinfo);
24096e91bba0SGirish Moodalbail 		if (!found) {
24106e91bba0SGirish Moodalbail 			return (0);
24116e91bba0SGirish Moodalbail 		}
24126e91bba0SGirish Moodalbail 		if (if_hostname_exists(ifinst, AF_INET) ||
24136e91bba0SGirish Moodalbail 		    if_hostname_exists(ifinst, AF_INET6)) {
24146e91bba0SGirish Moodalbail 			rcm_log_message(RCM_WARNING,
24156e91bba0SGirish Moodalbail 			    _("IP: IPv4 Post-attach (%s) found both "
24166e91bba0SGirish Moodalbail 			    "/etc/hostname and ipadm persistent configuration. "
24176e91bba0SGirish Moodalbail 			    "Ignoring ipadm config\n"), ifinst);
24186e91bba0SGirish Moodalbail 			return (0);
24196e91bba0SGirish Moodalbail 		}
24206e91bba0SGirish Moodalbail 		status = ipadm_enable_if(ip_handle, ifinst, IPADM_OPT_ACTIVE);
24216e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS) {
24226e91bba0SGirish Moodalbail 			rcm_log_message(RCM_ERROR,
24236e91bba0SGirish Moodalbail 			    _("IP: Post-attach failed (%s) Error %s\n"),
24246e91bba0SGirish Moodalbail 			    ifinst, ipadm_status2str(status));
24256e91bba0SGirish Moodalbail 			goto fail;
24266e91bba0SGirish Moodalbail 		}
24276e91bba0SGirish Moodalbail 	}
24286e91bba0SGirish Moodalbail done:
24296e91bba0SGirish Moodalbail 	rcm_log_message(RCM_TRACE1, "IP: if_configure_ipadm(%s) success\n",
24306e91bba0SGirish Moodalbail 	    ifinst);
24316e91bba0SGirish Moodalbail 	return (0);
24326e91bba0SGirish Moodalbail fail:
24336e91bba0SGirish Moodalbail 	return (-1);
24346e91bba0SGirish Moodalbail }
24356e91bba0SGirish Moodalbail 
24367c478bd9Sstevel@tonic-gate /*
2437e11c3f44Smeem  * isgrouped() - Scans the given config file to see if this interface is
2438e11c3f44Smeem  *	         using IPMP.  Returns B_TRUE or B_FALSE.
24397c478bd9Sstevel@tonic-gate  */
2440e11c3f44Smeem static boolean_t
isgrouped(const char * cfgfile)2441e11c3f44Smeem isgrouped(const char *cfgfile)
24427c478bd9Sstevel@tonic-gate {
24437c478bd9Sstevel@tonic-gate 	FILE *fp;
24447c478bd9Sstevel@tonic-gate 	struct stat statb;
2445e11c3f44Smeem 	char *nlp, *line, *token, *lasts, *buf;
2446e11c3f44Smeem 	boolean_t grouped = B_FALSE;
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile);
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 	if (stat(cfgfile, &statb) != 0) {
24517c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1,
24527c478bd9Sstevel@tonic-gate 		    _("IP: No config file(%s)\n"), cfgfile);
2453e11c3f44Smeem 		return (B_FALSE);
24547c478bd9Sstevel@tonic-gate 	}
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	/*
24577c478bd9Sstevel@tonic-gate 	 * We also ignore single-byte config files because the file should
24587c478bd9Sstevel@tonic-gate 	 * always be newline-terminated, so we know there's nothing of
24597c478bd9Sstevel@tonic-gate 	 * interest.  Further, a single-byte file would cause the fgets() loop
24607c478bd9Sstevel@tonic-gate 	 * below to spin forever.
24617c478bd9Sstevel@tonic-gate 	 */
24627c478bd9Sstevel@tonic-gate 	if (statb.st_size <= 1) {
24637c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1,
24647c478bd9Sstevel@tonic-gate 		    _("IP: Empty config file(%s)\n"), cfgfile);
2465e11c3f44Smeem 		return (B_FALSE);
24667c478bd9Sstevel@tonic-gate 	}
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 	if ((fp = fopen(cfgfile, "r")) == NULL) {
24697c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
24707c478bd9Sstevel@tonic-gate 		    _("IP: Cannot open configuration file(%s): %s\n"), cfgfile,
24717c478bd9Sstevel@tonic-gate 		    strerror(errno));
2472e11c3f44Smeem 		return (B_FALSE);
24737c478bd9Sstevel@tonic-gate 	}
24747c478bd9Sstevel@tonic-gate 
2475e11c3f44Smeem 	if ((buf = malloc(statb.st_size)) == NULL) {
24767c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
2477e11c3f44Smeem 		    _("IP: malloc failure(%s): %s\n"), cfgfile,
24787c478bd9Sstevel@tonic-gate 		    strerror(errno));
2479e11c3f44Smeem 		goto out;
24807c478bd9Sstevel@tonic-gate 	}
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 	while (fgets(buf, statb.st_size, fp) != NULL) {
2483e11c3f44Smeem 		if ((nlp = strrchr(buf, '\n')) != NULL)
2484e11c3f44Smeem 			*nlp = '\0';
2485e11c3f44Smeem 
2486e11c3f44Smeem 		line = buf;
2487e11c3f44Smeem 		while ((token = strtok_r(line, " \t", &lasts)) != NULL) {
2488e11c3f44Smeem 			line = NULL;
2489e11c3f44Smeem 			if (STREQ("group", token) &&
2490e11c3f44Smeem 			    strtok_r(NULL, " \t", &lasts) != NULL) {
2491e11c3f44Smeem 				grouped = B_TRUE;
2492e11c3f44Smeem 				goto out;
24937c478bd9Sstevel@tonic-gate 			}
24947c478bd9Sstevel@tonic-gate 		}
24957c478bd9Sstevel@tonic-gate 	}
2496e11c3f44Smeem out:
24977c478bd9Sstevel@tonic-gate 	free(buf);
24987c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
24997c478bd9Sstevel@tonic-gate 
2500e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s): %d\n", cfgfile,
2501e11c3f44Smeem 	    grouped);
25027c478bd9Sstevel@tonic-gate 
2503e11c3f44Smeem 	return (grouped);
2504e11c3f44Smeem }
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate /*
2507e11c3f44Smeem  * if_config_inst() - Configure an interface instance as specified by the
25087c478bd9Sstevel@tonic-gate  *		    address family af and if it is grouped (ipmp).
25097c478bd9Sstevel@tonic-gate  */
25107c478bd9Sstevel@tonic-gate static int
if_config_inst(const char * ifinst,FILE * hfp,int af,boolean_t ipmp)2511e11c3f44Smeem if_config_inst(const char *ifinst, FILE *hfp, int af, boolean_t ipmp)
25127c478bd9Sstevel@tonic-gate {
2513e11c3f44Smeem 	FILE *ifparsefp;
25147c478bd9Sstevel@tonic-gate 	struct stat statb;
2515e11c3f44Smeem 	char *buf = NULL;
2516e11c3f44Smeem 	char *ifparsebuf = NULL;
2517e11c3f44Smeem 	uint_t ifparsebufsize;
2518e11c3f44Smeem 	const char *fstr;		/* address family string */
2519e11c3f44Smeem 	boolean_t stdif = B_FALSE;
25207c478bd9Sstevel@tonic-gate 
2521e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) ipmp = %d\n",
25227c478bd9Sstevel@tonic-gate 	    ifinst, ipmp);
25237c478bd9Sstevel@tonic-gate 
2524e11c3f44Smeem 	if (fstat(fileno(hfp), &statb) != 0) {
2525e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
2526e11c3f44Smeem 		    _("IP: Cannot fstat file(%s)\n"), ifinst);
2527e11c3f44Smeem 		goto fail;
25287c478bd9Sstevel@tonic-gate 	}
25297c478bd9Sstevel@tonic-gate 
2530e11c3f44Smeem 	switch (af) {
2531e11c3f44Smeem 	case AF_INET:
2532e11c3f44Smeem 		fstr = "inet";
2533e11c3f44Smeem 		break;
2534e11c3f44Smeem 	case AF_INET6:
2535e11c3f44Smeem 		fstr = "inet6";
2536e11c3f44Smeem 		break;
2537e11c3f44Smeem 	default:
2538e11c3f44Smeem 		assert(0);
25397c478bd9Sstevel@tonic-gate 	}
25407c478bd9Sstevel@tonic-gate 
2541e11c3f44Smeem 	/*
2542e11c3f44Smeem 	 * The hostname file exists; plumb the physical interface.
2543e11c3f44Smeem 	 */
2544e11c3f44Smeem 	if (!ifconfig(ifinst, fstr, "plumb", B_FALSE))
2545e11c3f44Smeem 		goto fail;
25467c478bd9Sstevel@tonic-gate 
2547e11c3f44Smeem 	/* Skip static configuration if the hostname file is empty */
2548e11c3f44Smeem 	if (statb.st_size <= 1) {
25497c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1,
2550e11c3f44Smeem 		    _("IP: Zero size hostname file(%s)\n"), ifinst);
2551e11c3f44Smeem 		goto configured;
25527c478bd9Sstevel@tonic-gate 	}
25537c478bd9Sstevel@tonic-gate 
2554e11c3f44Smeem 	if (fseek(hfp, 0, SEEK_SET) == -1) {
25557c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
2556e11c3f44Smeem 		    _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2557e11c3f44Smeem 		    strerror(errno));
2558e11c3f44Smeem 		goto fail;
25597c478bd9Sstevel@tonic-gate 	}
25607c478bd9Sstevel@tonic-gate 
2561e11c3f44Smeem 	/*
2562e11c3f44Smeem 	 * Allocate the worst-case single-line buffer sizes.  A bit skanky,
2563e11c3f44Smeem 	 * but since hostname files are small, this should suffice.
2564e11c3f44Smeem 	 */
25657c478bd9Sstevel@tonic-gate 	if ((buf = calloc(1, statb.st_size)) == NULL) {
25667c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
25677c478bd9Sstevel@tonic-gate 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2568e11c3f44Smeem 		goto fail;
25697c478bd9Sstevel@tonic-gate 	}
25707c478bd9Sstevel@tonic-gate 
2571e11c3f44Smeem 	ifparsebufsize = statb.st_size + sizeof (SBIN_IFPARSE " -s inet6 ");
2572e11c3f44Smeem 	if ((ifparsebuf = calloc(1, ifparsebufsize)) == NULL) {
2573e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
2574e11c3f44Smeem 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2575e11c3f44Smeem 		goto fail;
25767c478bd9Sstevel@tonic-gate 	}
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	/*
2579e11c3f44Smeem 	 * For IPv4, determine whether the hostname file consists of a single
2580e11c3f44Smeem 	 * line.  We need to handle these specially since they should
2581e11c3f44Smeem 	 * automatically be suffixed with "netmask + broadcast + up".
25827c478bd9Sstevel@tonic-gate 	 */
2583e11c3f44Smeem 	if (af == AF_INET &&
2584e11c3f44Smeem 	    fgets(buf, statb.st_size, hfp) != NULL &&
2585e11c3f44Smeem 	    fgets(buf, statb.st_size, hfp) == NULL) {
2586e11c3f44Smeem 		rcm_log_message(RCM_TRACE1, "IP: one-line hostname file\n");
2587e11c3f44Smeem 		stdif = B_TRUE;
2588e11c3f44Smeem 	}
25897c478bd9Sstevel@tonic-gate 
2590e11c3f44Smeem 	if (fseek(hfp, 0L, SEEK_SET) == -1) {
2591e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
2592e11c3f44Smeem 		    _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2593e11c3f44Smeem 		    strerror(errno));
2594e11c3f44Smeem 		goto fail;
2595e11c3f44Smeem 	}
25967c478bd9Sstevel@tonic-gate 
2597e11c3f44Smeem 	/*
2598e11c3f44Smeem 	 * Loop through the file one line at a time and feed it to ifconfig.
2599e11c3f44Smeem 	 * If the interface is using IPMP, then we use /sbin/ifparse -s to
2600e11c3f44Smeem 	 * weed out all of the data addresses, since those are already on the
2601e11c3f44Smeem 	 * IPMP meta-interface.
2602e11c3f44Smeem 	 */
2603e11c3f44Smeem 	while (fgets(buf, statb.st_size, hfp) != NULL) {
2604e11c3f44Smeem 		if (ntok(buf) == 0)
26057c478bd9Sstevel@tonic-gate 			continue;
26067c478bd9Sstevel@tonic-gate 
2607e11c3f44Smeem 		if (!ipmp) {
2608e11c3f44Smeem 			(void) ifconfig(ifinst, fstr, buf, stdif);
26097c478bd9Sstevel@tonic-gate 			continue;
26107c478bd9Sstevel@tonic-gate 		}
26117c478bd9Sstevel@tonic-gate 
2612e11c3f44Smeem 		(void) snprintf(ifparsebuf, ifparsebufsize, SBIN_IFPARSE
2613e11c3f44Smeem 		    " -s %s %s", fstr, buf);
2614e11c3f44Smeem 		if ((ifparsefp = popen(ifparsebuf, "r")) == NULL) {
2615e11c3f44Smeem 			rcm_log_message(RCM_ERROR,
2616e11c3f44Smeem 			    _("IP: cannot configure %s: popen \"%s\" "
2617e11c3f44Smeem 			    "failed: %s\n"), ifinst, buf, strerror(errno));
2618e11c3f44Smeem 			goto fail;
26197c478bd9Sstevel@tonic-gate 		}
26207c478bd9Sstevel@tonic-gate 
2621e11c3f44Smeem 		while (fgets(buf, statb.st_size, ifparsefp) != NULL) {
2622e11c3f44Smeem 			if (ntok(buf) > 0)
2623e11c3f44Smeem 				(void) ifconfig(ifinst, fstr, buf, stdif);
26247c478bd9Sstevel@tonic-gate 		}
26257c478bd9Sstevel@tonic-gate 
2626e11c3f44Smeem 		if (pclose(ifparsefp) == -1) {
26277c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
2628e11c3f44Smeem 			    _("IP: cannot configure %s: pclose \"%s\" "
2629e11c3f44Smeem 			    "failed: %s\n"), ifinst, buf, strerror(errno));
2630e11c3f44Smeem 			goto fail;
26317c478bd9Sstevel@tonic-gate 		}
26327c478bd9Sstevel@tonic-gate 	}
26337c478bd9Sstevel@tonic-gate 
2634e11c3f44Smeem configured:
26357c478bd9Sstevel@tonic-gate 	/*
2636e11c3f44Smeem 	 * Bring up the interface (it may already be up)
2637e11c3f44Smeem 	 *
2638e11c3f44Smeem 	 * Technically, since the boot scripts only unconditionally bring up
2639e11c3f44Smeem 	 * IPv6 interfaces, we should only unconditionally bring up IPv6 here.
2640e11c3f44Smeem 	 * However, if we don't bring up IPv4, and a legacy IPMP configuration
2641e11c3f44Smeem 	 * without test addresses is being used, we will never bring the
2642e11c3f44Smeem 	 * interface up even though we would've at boot.  One fix is to check
2643e11c3f44Smeem 	 * if the IPv4 hostname file contains data addresses that we would've
2644e11c3f44Smeem 	 * brought up, but there's no simple way to do that.  Given that it's
2645e11c3f44Smeem 	 * rare to have persistent IP configuration for an interface that
2646e11c3f44Smeem 	 * leaves it down, we cheap out and always bring it up for IPMP.
26477c478bd9Sstevel@tonic-gate 	 */
2648e11c3f44Smeem 	if ((af == AF_INET6 || ipmp) && !ifconfig(ifinst, fstr, "up", B_FALSE))
2649e11c3f44Smeem 		goto fail;
26507c478bd9Sstevel@tonic-gate 
2651e11c3f44Smeem 	/*
2652e11c3f44Smeem 	 * For IPv4, if a DHCP configuration file exists, have DHCP configure
2653e11c3f44Smeem 	 * the interface.  As with the boot scripts, this is done after the
2654e11c3f44Smeem 	 * hostname files are processed so that configuration in those files
2655e11c3f44Smeem 	 * (such as IPMP group names) will be applied first.
2656e11c3f44Smeem 	 */
2657e11c3f44Smeem 	if (af == AF_INET) {
2658e11c3f44Smeem 		char dhcpfile[MAXPATHLEN];
2659e11c3f44Smeem 		char *dhcpbuf;
2660e11c3f44Smeem 		off_t i, dhcpsize;
26617c478bd9Sstevel@tonic-gate 
2662e11c3f44Smeem 		(void) snprintf(dhcpfile, MAXPATHLEN, DHCPFILE_FMT, ifinst);
2663e11c3f44Smeem 		if (stat(dhcpfile, &statb) == -1)
2664e11c3f44Smeem 			goto out;
26657c478bd9Sstevel@tonic-gate 
2666e11c3f44Smeem 		if ((dhcpbuf = copylist(dhcpfile, &dhcpsize)) == NULL) {
2667e11c3f44Smeem 			rcm_log_message(RCM_ERROR, _("IP: cannot read "
2668e11c3f44Smeem 			    "(%s): %s\n"), dhcpfile, strerror(errno));
2669e11c3f44Smeem 			goto fail;
26707c478bd9Sstevel@tonic-gate 		}
26717c478bd9Sstevel@tonic-gate 
2672e11c3f44Smeem 		/*
2673e11c3f44Smeem 		 * The copylist() API converts \n's to \0's, but we want them
2674e11c3f44Smeem 		 * to be spaces.
2675e11c3f44Smeem 		 */
2676e11c3f44Smeem 		if (dhcpsize > 0) {
2677e11c3f44Smeem 			for (i = 0; i < dhcpsize; i++)
2678e11c3f44Smeem 				if (dhcpbuf[i] == '\0')
2679e11c3f44Smeem 					dhcpbuf[i] = ' ';
2680e11c3f44Smeem 			dhcpbuf[dhcpsize - 1] = '\0';
26817c478bd9Sstevel@tonic-gate 		}
2682e11c3f44Smeem 		(void) ifconfig(ifinst, CFG_DHCP_CMD, dhcpbuf, B_FALSE);
2683e11c3f44Smeem 		free(dhcpbuf);
26847c478bd9Sstevel@tonic-gate 	}
2685e11c3f44Smeem out:
2686e11c3f44Smeem 	free(ifparsebuf);
26877c478bd9Sstevel@tonic-gate 	free(buf);
2688e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) success\n", ifinst);
2689e11c3f44Smeem 	return (0);
2690e11c3f44Smeem fail:
2691e11c3f44Smeem 	free(ifparsebuf);
2692e11c3f44Smeem 	free(buf);
2693e11c3f44Smeem 	rcm_log_message(RCM_ERROR, "IP: if_config_inst(%s) failure\n", ifinst);
2694e11c3f44Smeem 	return (-1);
26957c478bd9Sstevel@tonic-gate }
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate /*
2698e11c3f44Smeem  * ntok() - count the number of tokens in the provided buffer.
26997c478bd9Sstevel@tonic-gate  */
2700e11c3f44Smeem static uint_t
ntok(const char * cp)2701e11c3f44Smeem ntok(const char *cp)
27027c478bd9Sstevel@tonic-gate {
2703e11c3f44Smeem 	uint_t ntok = 0;
27047c478bd9Sstevel@tonic-gate 
2705e11c3f44Smeem 	for (;;) {
27067c478bd9Sstevel@tonic-gate 		while (ISSPACE(*cp))
27077c478bd9Sstevel@tonic-gate 			cp++;
2708e11c3f44Smeem 
27097c478bd9Sstevel@tonic-gate 		if (ISEOL(*cp))
27107c478bd9Sstevel@tonic-gate 			break;
2711e11c3f44Smeem 
27127c478bd9Sstevel@tonic-gate 		do {
2713e11c3f44Smeem 			cp++;
27147c478bd9Sstevel@tonic-gate 		} while (!ISSPACE(*cp) && !ISEOL(*cp));
27157c478bd9Sstevel@tonic-gate 
2716e11c3f44Smeem 		ntok++;
2717e11c3f44Smeem 	}
2718e11c3f44Smeem 	return (ntok);
2719e11c3f44Smeem }
2720e11c3f44Smeem 
2721e11c3f44Smeem static boolean_t
ifconfig(const char * ifinst,const char * fstr,const char * buf,boolean_t stdif)2722e11c3f44Smeem ifconfig(const char *ifinst, const char *fstr, const char *buf, boolean_t stdif)
2723e11c3f44Smeem {
2724e11c3f44Smeem 	char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
2725e11c3f44Smeem 	int status;
2726e11c3f44Smeem 
2727e11c3f44Smeem 	(void) snprintf(syscmd, sizeof (syscmd), SBIN_IFCONFIG " %s %s %s",
2728e11c3f44Smeem 	    ifinst, fstr, buf);
2729e11c3f44Smeem 
2730e11c3f44Smeem 	if (stdif)
2731e11c3f44Smeem 		(void) strlcat(syscmd, CFG_CMDS_STD, sizeof (syscmd));
2732e11c3f44Smeem 
2733e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd);
2734e11c3f44Smeem 	if ((status = rcm_exec_cmd(syscmd)) != 0) {
2735e11c3f44Smeem 		if (WIFEXITED(status)) {
2736e11c3f44Smeem 			rcm_log_message(RCM_ERROR, _("IP: \"%s\" failed with "
2737e11c3f44Smeem 			    "exit status %d\n"), syscmd, WEXITSTATUS(status));
2738e11c3f44Smeem 		} else {
2739e11c3f44Smeem 			rcm_log_message(RCM_ERROR, _("IP: Error: %s: %s\n"),
2740e11c3f44Smeem 			    syscmd, strerror(errno));
2741e11c3f44Smeem 		}
2742e11c3f44Smeem 		return (B_FALSE);
27437c478bd9Sstevel@tonic-gate 	}
2744e11c3f44Smeem 	return (B_TRUE);
27457c478bd9Sstevel@tonic-gate }
27466e91bba0SGirish Moodalbail 
27476e91bba0SGirish Moodalbail /*
27486e91bba0SGirish Moodalbail  * Return TRUE if a writeable /etc/hostname[6].ifname file exists.
27496e91bba0SGirish Moodalbail  */
27506e91bba0SGirish Moodalbail static boolean_t
if_hostname_exists(char * ifname,sa_family_t af)27516e91bba0SGirish Moodalbail if_hostname_exists(char *ifname, sa_family_t af)
27526e91bba0SGirish Moodalbail {
27536e91bba0SGirish Moodalbail 	char cfgfile[MAXPATHLEN];
27546e91bba0SGirish Moodalbail 
27556e91bba0SGirish Moodalbail 	if (af == AF_INET) {
27566e91bba0SGirish Moodalbail 		(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifname);
27576e91bba0SGirish Moodalbail 		if (access(cfgfile, W_OK|F_OK) == 0)
27586e91bba0SGirish Moodalbail 			return (B_TRUE);
27596e91bba0SGirish Moodalbail 	} else if (af == AF_INET6) {
27606e91bba0SGirish Moodalbail 		(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifname);
27616e91bba0SGirish Moodalbail 		if (access(cfgfile, W_OK|F_OK) == 0)
27626e91bba0SGirish Moodalbail 			return (B_TRUE);
27636e91bba0SGirish Moodalbail 	}
27646e91bba0SGirish Moodalbail 	return (B_FALSE);
27656e91bba0SGirish Moodalbail }
2766