xref: /titanic_41/usr/src/cmd/cmd-inet/usr.lib/in.mpathd/mpd_tables.c (revision 9bea609830e5d4083cf3cd9a11ab54699ca62b3e)
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
5921e7e07Smeem  * Common Development and Distribution License (the "License").
6921e7e07Smeem  * 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 /*
22e11c3f44Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include "mpd_defs.h"
277c478bd9Sstevel@tonic-gate #include "mpd_tables.h"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Global list of phyints, phyint instances, phyint groups and the anonymous
317c478bd9Sstevel@tonic-gate  * group; the latter is initialized in phyint_init().
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate struct phyint *phyints = NULL;
347c478bd9Sstevel@tonic-gate struct phyint_instance	*phyint_instances = NULL;
357c478bd9Sstevel@tonic-gate struct phyint_group *phyint_groups = NULL;
367c478bd9Sstevel@tonic-gate struct phyint_group *phyint_anongroup;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * Grouplist signature; initialized in phyint_init().
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate static uint64_t phyint_grouplistsig;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate static void phyint_inst_insert(struct phyint_instance *pii);
447c478bd9Sstevel@tonic-gate static void phyint_inst_print(struct phyint_instance *pii);
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate static void phyint_insert(struct phyint *pi, struct phyint_group *pg);
477c478bd9Sstevel@tonic-gate static void phyint_delete(struct phyint *pi);
48e11c3f44Smeem static boolean_t phyint_is_usable(struct phyint *pi);
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static void logint_print(struct logint *li);
517c478bd9Sstevel@tonic-gate static void logint_insert(struct phyint_instance *pii, struct logint *li);
527c478bd9Sstevel@tonic-gate static struct logint *logint_lookup(struct phyint_instance *pii, char *li_name);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate static void target_print(struct target *tg);
557c478bd9Sstevel@tonic-gate static void target_insert(struct phyint_instance *pii, struct target *tg);
567c478bd9Sstevel@tonic-gate static struct target *target_first(struct phyint_instance *pii);
577c478bd9Sstevel@tonic-gate static struct target *target_select_best(struct phyint_instance *pii);
587c478bd9Sstevel@tonic-gate static void target_flush_hosts(struct phyint_group *pg);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate static void reset_pii_probes(struct phyint_instance *pii, struct target *tg);
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static boolean_t phyint_inst_v6_sockinit(struct phyint_instance *pii);
637c478bd9Sstevel@tonic-gate static boolean_t phyint_inst_v4_sockinit(struct phyint_instance *pii);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static int phyint_state_event(struct phyint_group *pg, struct phyint *pi);
667c478bd9Sstevel@tonic-gate static int phyint_group_state_event(struct phyint_group *pg);
677c478bd9Sstevel@tonic-gate static int phyint_group_change_event(struct phyint_group *pg, ipmp_group_op_t);
687c478bd9Sstevel@tonic-gate static int phyint_group_member_event(struct phyint_group *pg, struct phyint *pi,
697c478bd9Sstevel@tonic-gate     ipmp_if_op_t op);
707c478bd9Sstevel@tonic-gate 
71e11c3f44Smeem static int logint_upcount(struct phyint *pi);
727c478bd9Sstevel@tonic-gate static uint64_t gensig(void);
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /* Initialize any per-file global state.  Returns 0 on success, -1 on failure */
757c478bd9Sstevel@tonic-gate int
phyint_init(void)767c478bd9Sstevel@tonic-gate phyint_init(void)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	phyint_grouplistsig = gensig();
797c478bd9Sstevel@tonic-gate 	if (track_all_phyints) {
807c478bd9Sstevel@tonic-gate 		phyint_anongroup = phyint_group_create("");
817c478bd9Sstevel@tonic-gate 		if (phyint_anongroup == NULL)
827c478bd9Sstevel@tonic-gate 			return (-1);
837c478bd9Sstevel@tonic-gate 		phyint_group_insert(phyint_anongroup);
847c478bd9Sstevel@tonic-gate 	}
857c478bd9Sstevel@tonic-gate 	return (0);
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /* Return the phyint with the given name */
897c478bd9Sstevel@tonic-gate struct phyint *
phyint_lookup(const char * name)907c478bd9Sstevel@tonic-gate phyint_lookup(const char *name)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	struct phyint *pi;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
957c478bd9Sstevel@tonic-gate 		logdebug("phyint_lookup(%s)\n", name);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
987c478bd9Sstevel@tonic-gate 		if (strncmp(pi->pi_name, name, sizeof (pi->pi_name)) == 0)
997c478bd9Sstevel@tonic-gate 			break;
1007c478bd9Sstevel@tonic-gate 	}
1017c478bd9Sstevel@tonic-gate 	return (pi);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
104e11c3f44Smeem /*
105e11c3f44Smeem  * Lookup a phyint in the group that has the same hardware address as `pi', or
106e11c3f44Smeem  * NULL if there's none.  If `online_only' is set, then only online phyints
107e11c3f44Smeem  * are considered when matching.  Otherwise, phyints that had been offlined
108e11c3f44Smeem  * due to a duplicate hardware address will also be considered.
109e11c3f44Smeem  */
110e11c3f44Smeem static struct phyint *
phyint_lookup_hwaddr(struct phyint * pi,boolean_t online_only)111e11c3f44Smeem phyint_lookup_hwaddr(struct phyint *pi, boolean_t online_only)
112e11c3f44Smeem {
113e11c3f44Smeem 	struct phyint *pi2;
114e11c3f44Smeem 
115e11c3f44Smeem 	if (pi->pi_group == phyint_anongroup)
116e11c3f44Smeem 		return (NULL);
117e11c3f44Smeem 
118e11c3f44Smeem 	for (pi2 = pi->pi_group->pg_phyint; pi2 != NULL; pi2 = pi2->pi_pgnext) {
119e11c3f44Smeem 		if (pi2 == pi)
120e11c3f44Smeem 			continue;
121e11c3f44Smeem 
122e11c3f44Smeem 		/*
123e11c3f44Smeem 		 * NOTE: even when online_only is B_FALSE, we ignore phyints
124e11c3f44Smeem 		 * that are administratively offline (rather than offline
125e11c3f44Smeem 		 * because they're dups); when they're brought back online,
126e11c3f44Smeem 		 * they'll be flagged as dups if need be.
127e11c3f44Smeem 		 */
128e11c3f44Smeem 		if (pi2->pi_state == PI_OFFLINE &&
129e11c3f44Smeem 		    (online_only || !pi2->pi_hwaddrdup))
130e11c3f44Smeem 			continue;
131e11c3f44Smeem 
132e11c3f44Smeem 		if (pi2->pi_hwaddrlen == pi->pi_hwaddrlen &&
133e11c3f44Smeem 		    bcmp(pi2->pi_hwaddr, pi->pi_hwaddr, pi->pi_hwaddrlen) == 0)
134e11c3f44Smeem 			return (pi2);
135e11c3f44Smeem 	}
136e11c3f44Smeem 	return (NULL);
137e11c3f44Smeem }
138e11c3f44Smeem 
139e11c3f44Smeem /*
140e11c3f44Smeem  * Respond to DLPI notifications.  Currently, this only processes physical
141e11c3f44Smeem  * address changes for the phyint passed via `arg' by onlining or offlining
142e11c3f44Smeem  * phyints in the group.
143e11c3f44Smeem  */
144e11c3f44Smeem /* ARGSUSED */
145e11c3f44Smeem static void
phyint_link_notify(dlpi_handle_t dh,dlpi_notifyinfo_t * dnip,void * arg)146e11c3f44Smeem phyint_link_notify(dlpi_handle_t dh, dlpi_notifyinfo_t *dnip, void *arg)
147e11c3f44Smeem {
148e11c3f44Smeem 	struct phyint *pi = arg;
149e11c3f44Smeem 	struct phyint *oduppi = NULL, *duppi = NULL;
150e11c3f44Smeem 
151e11c3f44Smeem 	assert((dnip->dni_note & pi->pi_notes) != 0);
152e11c3f44Smeem 
153e11c3f44Smeem 	if (dnip->dni_note != DL_NOTE_PHYS_ADDR)
154e11c3f44Smeem 		return;
155e11c3f44Smeem 
156e11c3f44Smeem 	assert(dnip->dni_physaddrlen <= DLPI_PHYSADDR_MAX);
157e11c3f44Smeem 
158e11c3f44Smeem 	/*
159e11c3f44Smeem 	 * If our hardware address hasn't changed, there's nothing to do.
160e11c3f44Smeem 	 */
161e11c3f44Smeem 	if (pi->pi_hwaddrlen == dnip->dni_physaddrlen &&
162e11c3f44Smeem 	    bcmp(pi->pi_hwaddr, dnip->dni_physaddr, pi->pi_hwaddrlen) == 0)
163e11c3f44Smeem 		return;
164e11c3f44Smeem 
165e11c3f44Smeem 	oduppi = phyint_lookup_hwaddr(pi, _B_FALSE);
166e11c3f44Smeem 	pi->pi_hwaddrlen = dnip->dni_physaddrlen;
167e11c3f44Smeem 	(void) memcpy(pi->pi_hwaddr, dnip->dni_physaddr, pi->pi_hwaddrlen);
168e11c3f44Smeem 	duppi = phyint_lookup_hwaddr(pi, _B_FALSE);
169e11c3f44Smeem 
170e11c3f44Smeem 	if (oduppi != NULL || pi->pi_hwaddrdup) {
171e11c3f44Smeem 		/*
172e11c3f44Smeem 		 * Our old hardware address was a duplicate.  If we'd been
173e11c3f44Smeem 		 * offlined because of it, and our new hardware address is not
174e11c3f44Smeem 		 * a duplicate, then bring us online.  Otherwise, `oduppi'
175e11c3f44Smeem 		 * must've been the one brought offline; bring it online.
176e11c3f44Smeem 		 */
177e11c3f44Smeem 		if (pi->pi_hwaddrdup) {
178e11c3f44Smeem 			if (duppi == NULL)
179e11c3f44Smeem 				(void) phyint_undo_offline(pi);
180e11c3f44Smeem 		} else {
181e11c3f44Smeem 			assert(oduppi->pi_hwaddrdup);
182e11c3f44Smeem 			(void) phyint_undo_offline(oduppi);
183e11c3f44Smeem 		}
184e11c3f44Smeem 	}
185e11c3f44Smeem 
186e11c3f44Smeem 	if (duppi != NULL && !pi->pi_hwaddrdup) {
187e11c3f44Smeem 		/*
188e11c3f44Smeem 		 * Our new hardware address was a duplicate and we're not
189e11c3f44Smeem 		 * yet flagged as a duplicate; bring us offline.
190e11c3f44Smeem 		 */
191e11c3f44Smeem 		pi->pi_hwaddrdup = _B_TRUE;
192e11c3f44Smeem 		(void) phyint_offline(pi, 0);
193e11c3f44Smeem 	}
194e11c3f44Smeem }
195e11c3f44Smeem 
196e11c3f44Smeem /*
197e11c3f44Smeem  * Initialize information about the underlying link for `pi', and set us
198e11c3f44Smeem  * up to be notified about future changes.  Returns _B_TRUE on success.
199e11c3f44Smeem  */
200e11c3f44Smeem boolean_t
phyint_link_init(struct phyint * pi)201e11c3f44Smeem phyint_link_init(struct phyint *pi)
202e11c3f44Smeem {
203e11c3f44Smeem 	int retval;
204e11c3f44Smeem 	uint_t notes;
205e11c3f44Smeem 	const char *errmsg;
206e11c3f44Smeem 	dlpi_notifyid_t id;
207e11c3f44Smeem 
208e11c3f44Smeem 	pi->pi_notes = 0;
209e11c3f44Smeem 	retval = dlpi_open(pi->pi_name, &pi->pi_dh, 0);
210e11c3f44Smeem 	if (retval != DLPI_SUCCESS) {
211e11c3f44Smeem 		pi->pi_dh = NULL;
212e11c3f44Smeem 		errmsg = "cannot open";
213e11c3f44Smeem 		goto failed;
214e11c3f44Smeem 	}
215e11c3f44Smeem 
216e11c3f44Smeem 	pi->pi_hwaddrlen = DLPI_PHYSADDR_MAX;
217e11c3f44Smeem 	retval = dlpi_get_physaddr(pi->pi_dh, DL_CURR_PHYS_ADDR, pi->pi_hwaddr,
218e11c3f44Smeem 	    &pi->pi_hwaddrlen);
219e11c3f44Smeem 	if (retval != DLPI_SUCCESS) {
220e11c3f44Smeem 		errmsg = "cannot get hardware address";
221e11c3f44Smeem 		goto failed;
222e11c3f44Smeem 	}
223e11c3f44Smeem 
224e11c3f44Smeem 	/*
225e11c3f44Smeem 	 * Check if the link supports DLPI link state notifications.  For
226e11c3f44Smeem 	 * historical reasons, the actual changes are tracked through routing
227e11c3f44Smeem 	 * sockets, so we immediately disable the notification upon success.
228e11c3f44Smeem 	 */
229e11c3f44Smeem 	notes = DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN;
230e11c3f44Smeem 	retval = dlpi_enabnotify(pi->pi_dh, notes, phyint_link_notify, pi, &id);
231e11c3f44Smeem 	if (retval == DLPI_SUCCESS) {
232e11c3f44Smeem 		(void) dlpi_disabnotify(pi->pi_dh, id, NULL);
233e11c3f44Smeem 		pi->pi_notes |= notes;
234e11c3f44Smeem 	}
235e11c3f44Smeem 
236e11c3f44Smeem 	/*
237e11c3f44Smeem 	 * Enable notification of hardware address changes to keep pi_hwaddr
238e11c3f44Smeem 	 * up-to-date and track if we need to offline/undo-offline phyints.
239e11c3f44Smeem 	 */
240e11c3f44Smeem 	notes = DL_NOTE_PHYS_ADDR;
241e11c3f44Smeem 	retval = dlpi_enabnotify(pi->pi_dh, notes, phyint_link_notify, pi, &id);
242e11c3f44Smeem 	if (retval == DLPI_SUCCESS && poll_add(dlpi_fd(pi->pi_dh)) == 0)
243e11c3f44Smeem 		pi->pi_notes |= notes;
244e11c3f44Smeem 
245e11c3f44Smeem 	return (_B_TRUE);
246e11c3f44Smeem failed:
247e11c3f44Smeem 	logerr("%s: %s: %s\n", pi->pi_name, errmsg, dlpi_strerror(retval));
248e11c3f44Smeem 	if (pi->pi_dh != NULL) {
249e11c3f44Smeem 		dlpi_close(pi->pi_dh);
250e11c3f44Smeem 		pi->pi_dh = NULL;
251e11c3f44Smeem 	}
252e11c3f44Smeem 	return (_B_FALSE);
253e11c3f44Smeem }
254e11c3f44Smeem 
255e11c3f44Smeem /*
256e11c3f44Smeem  * Close use of link on `pi'.
257e11c3f44Smeem  */
258e11c3f44Smeem void
phyint_link_close(struct phyint * pi)259e11c3f44Smeem phyint_link_close(struct phyint *pi)
260e11c3f44Smeem {
261e11c3f44Smeem 	if (pi->pi_notes & DL_NOTE_PHYS_ADDR) {
262e11c3f44Smeem 		(void) poll_remove(dlpi_fd(pi->pi_dh));
263e11c3f44Smeem 		pi->pi_notes &= ~DL_NOTE_PHYS_ADDR;
264e11c3f44Smeem 	}
265e11c3f44Smeem 
266e11c3f44Smeem 	/*
267e11c3f44Smeem 	 * NOTE: we don't clear pi_notes here so that iflinkstate() can still
268e11c3f44Smeem 	 * properly report the link state even when offline (which is possible
269e11c3f44Smeem 	 * since we use IFF_RUNNING to track link state).
270e11c3f44Smeem 	 */
271e11c3f44Smeem 	dlpi_close(pi->pi_dh);
272e11c3f44Smeem 	pi->pi_dh = NULL;
273e11c3f44Smeem }
274e11c3f44Smeem 
2757c478bd9Sstevel@tonic-gate /* Return the phyint instance with the given name and the given family */
2767c478bd9Sstevel@tonic-gate struct phyint_instance *
phyint_inst_lookup(int af,char * name)2777c478bd9Sstevel@tonic-gate phyint_inst_lookup(int af, char *name)
2787c478bd9Sstevel@tonic-gate {
2797c478bd9Sstevel@tonic-gate 	struct phyint *pi;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
2827c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_lookup(%s %s)\n", AF_STR(af), name);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	assert(af == AF_INET || af == AF_INET6);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	pi = phyint_lookup(name);
2877c478bd9Sstevel@tonic-gate 	if (pi == NULL)
2887c478bd9Sstevel@tonic-gate 		return (NULL);
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	return (PHYINT_INSTANCE(pi, af));
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
293e11c3f44Smeem struct phyint_group *
phyint_group_lookup(const char * pg_name)2947c478bd9Sstevel@tonic-gate phyint_group_lookup(const char *pg_name)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	struct phyint_group *pg;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
2997c478bd9Sstevel@tonic-gate 		logdebug("phyint_group_lookup(%s)\n", pg_name);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	for (pg = phyint_groups; pg != NULL; pg = pg->pg_next) {
3027c478bd9Sstevel@tonic-gate 		if (strncmp(pg->pg_name, pg_name, sizeof (pg->pg_name)) == 0)
3037c478bd9Sstevel@tonic-gate 			break;
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	return (pg);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate  * Insert the phyint in the linked list of all phyints. If the phyint belongs
3107c478bd9Sstevel@tonic-gate  * to some group, insert it in the phyint group list.
3117c478bd9Sstevel@tonic-gate  */
3127c478bd9Sstevel@tonic-gate static void
phyint_insert(struct phyint * pi,struct phyint_group * pg)3137c478bd9Sstevel@tonic-gate phyint_insert(struct phyint *pi, struct phyint_group *pg)
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
3167c478bd9Sstevel@tonic-gate 		logdebug("phyint_insert(%s '%s')\n", pi->pi_name, pg->pg_name);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	/* Insert the phyint at the head of the 'all phyints' list */
3197c478bd9Sstevel@tonic-gate 	pi->pi_next = phyints;
3207c478bd9Sstevel@tonic-gate 	pi->pi_prev = NULL;
3217c478bd9Sstevel@tonic-gate 	if (phyints != NULL)
3227c478bd9Sstevel@tonic-gate 		phyints->pi_prev = pi;
3237c478bd9Sstevel@tonic-gate 	phyints = pi;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/*
3267c478bd9Sstevel@tonic-gate 	 * Insert the phyint at the head of the 'phyint_group members' list
3277c478bd9Sstevel@tonic-gate 	 * of the phyint group to which it belongs.
3287c478bd9Sstevel@tonic-gate 	 */
3297c478bd9Sstevel@tonic-gate 	pi->pi_pgnext = NULL;
3307c478bd9Sstevel@tonic-gate 	pi->pi_pgprev = NULL;
3317c478bd9Sstevel@tonic-gate 	pi->pi_group = pg;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	pi->pi_pgnext = pg->pg_phyint;
3347c478bd9Sstevel@tonic-gate 	if (pi->pi_pgnext != NULL)
3357c478bd9Sstevel@tonic-gate 		pi->pi_pgnext->pi_pgprev = pi;
3367c478bd9Sstevel@tonic-gate 	pg->pg_phyint = pi;
3377c478bd9Sstevel@tonic-gate 
338e11c3f44Smeem 	/* Refresh the group state now that this phyint has been added */
339e11c3f44Smeem 	phyint_group_refresh_state(pg);
340e11c3f44Smeem 
3417c478bd9Sstevel@tonic-gate 	pg->pg_sig++;
3427c478bd9Sstevel@tonic-gate 	(void) phyint_group_member_event(pg, pi, IPMP_IF_ADD);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /* Insert the phyint instance in the linked list of all phyint instances. */
3467c478bd9Sstevel@tonic-gate static void
phyint_inst_insert(struct phyint_instance * pii)3477c478bd9Sstevel@tonic-gate phyint_inst_insert(struct phyint_instance *pii)
3487c478bd9Sstevel@tonic-gate {
3497c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
3507c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_insert(%s %s)\n",
3517c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name);
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	/*
3557c478bd9Sstevel@tonic-gate 	 * Insert the phyint at the head of the 'all phyint instances' list.
3567c478bd9Sstevel@tonic-gate 	 */
3577c478bd9Sstevel@tonic-gate 	pii->pii_next = phyint_instances;
3587c478bd9Sstevel@tonic-gate 	pii->pii_prev = NULL;
3597c478bd9Sstevel@tonic-gate 	if (phyint_instances != NULL)
3607c478bd9Sstevel@tonic-gate 		phyint_instances->pii_prev = pii;
3617c478bd9Sstevel@tonic-gate 	phyint_instances = pii;
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate /*
3657c478bd9Sstevel@tonic-gate  * Create a new phyint with the given parameters. Also insert it into
3667c478bd9Sstevel@tonic-gate  * the list of all phyints and the list of phyint group members by calling
3677c478bd9Sstevel@tonic-gate  * phyint_insert().
3687c478bd9Sstevel@tonic-gate  */
3697c478bd9Sstevel@tonic-gate static struct phyint *
phyint_create(char * pi_name,struct phyint_group * pg,uint_t ifindex,uint64_t flags)3707c478bd9Sstevel@tonic-gate phyint_create(char *pi_name, struct phyint_group *pg, uint_t ifindex,
3717c478bd9Sstevel@tonic-gate     uint64_t flags)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	struct phyint *pi;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	pi = calloc(1, sizeof (struct phyint));
3767c478bd9Sstevel@tonic-gate 	if (pi == NULL) {
3777c478bd9Sstevel@tonic-gate 		logperror("phyint_create: calloc");
3787c478bd9Sstevel@tonic-gate 		return (NULL);
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	/*
382e11c3f44Smeem 	 * Record the phyint values.
3837c478bd9Sstevel@tonic-gate 	 */
384e6ed03fcSmeem 	(void) strlcpy(pi->pi_name, pi_name, sizeof (pi->pi_name));
385e6ed03fcSmeem 	pi->pi_taddrthresh = getcurrentsec() + TESTADDR_CONF_TIME;
3867c478bd9Sstevel@tonic-gate 	pi->pi_ifindex = ifindex;
387e11c3f44Smeem 	pi->pi_icmpid = htons(((getpid() & 0xFF) << 8) | (ifindex & 0xFF));
388e11c3f44Smeem 
389fcdc8680Smeem 	pi->pi_state = PI_INIT;
3907c478bd9Sstevel@tonic-gate 	pi->pi_flags = PHYINT_FLAGS(flags);
391e11c3f44Smeem 
3927c478bd9Sstevel@tonic-gate 	/*
393c445e3e1Smeem 	 * Initialize the link state.  The link state is initialized to
3947c478bd9Sstevel@tonic-gate 	 * up, so that if the link is down when IPMP starts monitoring
3957c478bd9Sstevel@tonic-gate 	 * the interface, it will appear as though there has been a
3967c478bd9Sstevel@tonic-gate 	 * transition from the link up to link down.  This avoids
3977c478bd9Sstevel@tonic-gate 	 * having to treat this situation as a special case.
3987c478bd9Sstevel@tonic-gate 	 */
3997c478bd9Sstevel@tonic-gate 	INIT_LINK_STATE(pi);
4007c478bd9Sstevel@tonic-gate 
401e11c3f44Smeem 	if (!phyint_link_init(pi)) {
402e11c3f44Smeem 		free(pi);
403e11c3f44Smeem 		return (NULL);
404e11c3f44Smeem 	}
405e11c3f44Smeem 
4067c478bd9Sstevel@tonic-gate 	/*
4077c478bd9Sstevel@tonic-gate 	 * Insert the phyint in the list of all phyints, and the
4087c478bd9Sstevel@tonic-gate 	 * list of phyint group members
4097c478bd9Sstevel@tonic-gate 	 */
4107c478bd9Sstevel@tonic-gate 	phyint_insert(pi, pg);
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	return (pi);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate /*
4167c478bd9Sstevel@tonic-gate  * Create a new phyint instance belonging to the phyint 'pi' and address
4177c478bd9Sstevel@tonic-gate  * family 'af'. Also insert it into the list of all phyint instances by
4187c478bd9Sstevel@tonic-gate  * calling phyint_inst_insert().
4197c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate static struct phyint_instance *
phyint_inst_create(struct phyint * pi,int af)4217c478bd9Sstevel@tonic-gate phyint_inst_create(struct phyint *pi, int af)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	pii = calloc(1, sizeof (struct phyint_instance));
4267c478bd9Sstevel@tonic-gate 	if (pii == NULL) {
4277c478bd9Sstevel@tonic-gate 		logperror("phyint_inst_create: calloc");
4287c478bd9Sstevel@tonic-gate 		return (NULL);
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	/*
4327c478bd9Sstevel@tonic-gate 	 * Attach the phyint instance to the phyint.
4337c478bd9Sstevel@tonic-gate 	 * Set the back pointers as well
4347c478bd9Sstevel@tonic-gate 	 */
4357c478bd9Sstevel@tonic-gate 	pii->pii_phyint = pi;
4367c478bd9Sstevel@tonic-gate 	if (af == AF_INET)
4377c478bd9Sstevel@tonic-gate 		pi->pi_v4 = pii;
4387c478bd9Sstevel@tonic-gate 	else
4397c478bd9Sstevel@tonic-gate 		pi->pi_v6 = pii;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	pii->pii_in_use = 1;
4427c478bd9Sstevel@tonic-gate 	pii->pii_probe_sock = -1;
4437c478bd9Sstevel@tonic-gate 	pii->pii_snxt = 1;
4447c478bd9Sstevel@tonic-gate 	pii->pii_af = af;
4457c478bd9Sstevel@tonic-gate 	pii->pii_fd_hrtime = gethrtime() +
4467c478bd9Sstevel@tonic-gate 	    (FAILURE_DETECTION_QP * (hrtime_t)NANOSEC);
4477c478bd9Sstevel@tonic-gate 	pii->pii_flags = pi->pi_flags;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	/* Insert the phyint instance in the list of all phyint instances. */
4507c478bd9Sstevel@tonic-gate 	phyint_inst_insert(pii);
4517c478bd9Sstevel@tonic-gate 	return (pii);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate  * Change the state of phyint `pi' to state `state'.
4567c478bd9Sstevel@tonic-gate  */
4577c478bd9Sstevel@tonic-gate void
phyint_chstate(struct phyint * pi,enum pi_state state)4587c478bd9Sstevel@tonic-gate phyint_chstate(struct phyint *pi, enum pi_state state)
4597c478bd9Sstevel@tonic-gate {
4607c478bd9Sstevel@tonic-gate 	/*
4617c478bd9Sstevel@tonic-gate 	 * To simplify things, some callers always set a given state
4627c478bd9Sstevel@tonic-gate 	 * regardless of the previous state of the phyint (e.g., setting
4637c478bd9Sstevel@tonic-gate 	 * PI_RUNNING when it's already set).  We shouldn't bother
4647c478bd9Sstevel@tonic-gate 	 * generating an event or consuming a signature for these, since
4657c478bd9Sstevel@tonic-gate 	 * the actual state of the interface is unchanged.
4667c478bd9Sstevel@tonic-gate 	 */
4677c478bd9Sstevel@tonic-gate 	if (pi->pi_state == state)
4687c478bd9Sstevel@tonic-gate 		return;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	pi->pi_state = state;
471e11c3f44Smeem 	phyint_changed(pi);
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate /*
475e11c3f44Smeem  * Note that `pi' has changed state.
4767c478bd9Sstevel@tonic-gate  */
4777c478bd9Sstevel@tonic-gate void
phyint_changed(struct phyint * pi)478e11c3f44Smeem phyint_changed(struct phyint *pi)
4797c478bd9Sstevel@tonic-gate {
4807c478bd9Sstevel@tonic-gate 	pi->pi_group->pg_sig++;
4817c478bd9Sstevel@tonic-gate 	(void) phyint_state_event(pi->pi_group, pi);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate /*
4857c478bd9Sstevel@tonic-gate  * Insert the phyint group in the linked list of all phyint groups
4867c478bd9Sstevel@tonic-gate  * at the head of the list
4877c478bd9Sstevel@tonic-gate  */
488e11c3f44Smeem void
phyint_group_insert(struct phyint_group * pg)4897c478bd9Sstevel@tonic-gate phyint_group_insert(struct phyint_group *pg)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	pg->pg_next = phyint_groups;
4927c478bd9Sstevel@tonic-gate 	pg->pg_prev = NULL;
4937c478bd9Sstevel@tonic-gate 	if (phyint_groups != NULL)
4947c478bd9Sstevel@tonic-gate 		phyint_groups->pg_prev = pg;
4957c478bd9Sstevel@tonic-gate 	phyint_groups = pg;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	phyint_grouplistsig++;
4987c478bd9Sstevel@tonic-gate 	(void) phyint_group_change_event(pg, IPMP_GROUP_ADD);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate /*
5027c478bd9Sstevel@tonic-gate  * Create a new phyint group called 'name'.
5037c478bd9Sstevel@tonic-gate  */
504e11c3f44Smeem struct phyint_group *
phyint_group_create(const char * name)5057c478bd9Sstevel@tonic-gate phyint_group_create(const char *name)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate 	struct	phyint_group *pg;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
5107c478bd9Sstevel@tonic-gate 		logdebug("phyint_group_create(%s)\n", name);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	pg = calloc(1, sizeof (struct phyint_group));
5137c478bd9Sstevel@tonic-gate 	if (pg == NULL) {
5147c478bd9Sstevel@tonic-gate 		logperror("phyint_group_create: calloc");
5157c478bd9Sstevel@tonic-gate 		return (NULL);
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 
518e6ed03fcSmeem 	(void) strlcpy(pg->pg_name, name, sizeof (pg->pg_name));
5197c478bd9Sstevel@tonic-gate 	pg->pg_sig = gensig();
5207c478bd9Sstevel@tonic-gate 	pg->pg_fdt = user_failure_detection_time;
5217c478bd9Sstevel@tonic-gate 	pg->pg_probeint = user_probe_interval;
522e11c3f44Smeem 	pg->pg_in_use = _B_TRUE;
523e11c3f44Smeem 
524e11c3f44Smeem 	/*
525e11c3f44Smeem 	 * Normal groups always start in the PG_FAILED state since they
526e11c3f44Smeem 	 * have no active interfaces.  In contrast, anonymous groups are
527e11c3f44Smeem 	 * heterogeneous and thus always PG_OK.
528e11c3f44Smeem 	 */
529e11c3f44Smeem 	pg->pg_state = (name[0] == '\0' ? PG_OK : PG_FAILED);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	return (pg);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate /*
5357c478bd9Sstevel@tonic-gate  * Change the state of the phyint group `pg' to state `state'.
5367c478bd9Sstevel@tonic-gate  */
5377c478bd9Sstevel@tonic-gate void
phyint_group_chstate(struct phyint_group * pg,enum pg_state state)5387c478bd9Sstevel@tonic-gate phyint_group_chstate(struct phyint_group *pg, enum pg_state state)
5397c478bd9Sstevel@tonic-gate {
5407c478bd9Sstevel@tonic-gate 	assert(pg != phyint_anongroup);
5417c478bd9Sstevel@tonic-gate 
542e11c3f44Smeem 	/*
543e11c3f44Smeem 	 * To simplify things, some callers always set a given state
544e11c3f44Smeem 	 * regardless of the previous state of the group (e.g., setting
545e11c3f44Smeem 	 * PG_DEGRADED when it's already set).  We shouldn't bother
546e11c3f44Smeem 	 * generating an event or consuming a signature for these, since
547e11c3f44Smeem 	 * the actual state of the group is unchanged.
548e11c3f44Smeem 	 */
549e11c3f44Smeem 	if (pg->pg_state == state)
550e11c3f44Smeem 		return;
551e11c3f44Smeem 
552e11c3f44Smeem 	pg->pg_state = state;
553e11c3f44Smeem 
5547c478bd9Sstevel@tonic-gate 	switch (state) {
5557c478bd9Sstevel@tonic-gate 	case PG_FAILED:
5567c478bd9Sstevel@tonic-gate 		/*
5577c478bd9Sstevel@tonic-gate 		 * We can never know with certainty that a group has
5587c478bd9Sstevel@tonic-gate 		 * failed.  It is possible that all known targets have
5597c478bd9Sstevel@tonic-gate 		 * failed simultaneously, and new targets have come up
5607c478bd9Sstevel@tonic-gate 		 * instead. If the targets are routers then router
5617c478bd9Sstevel@tonic-gate 		 * discovery will kick in, and we will see the new routers
5627c478bd9Sstevel@tonic-gate 		 * thru routing socket messages. But if the targets are
5637c478bd9Sstevel@tonic-gate 		 * hosts, we have to discover it by multicast.	So flush
5647c478bd9Sstevel@tonic-gate 		 * all the host targets. The next probe will send out a
5657c478bd9Sstevel@tonic-gate 		 * multicast echo request. If this is a group failure, we
566e11c3f44Smeem 		 * will still not see any response, otherwise the group
567e11c3f44Smeem 		 * will be repaired after we get NUM_PROBE_REPAIRS
568e11c3f44Smeem 		 * consecutive unicast replies on any phyint.
5697c478bd9Sstevel@tonic-gate 		 */
5707c478bd9Sstevel@tonic-gate 		target_flush_hosts(pg);
5717c478bd9Sstevel@tonic-gate 		break;
5727c478bd9Sstevel@tonic-gate 
573e11c3f44Smeem 	case PG_OK:
574e11c3f44Smeem 	case PG_DEGRADED:
5757c478bd9Sstevel@tonic-gate 		break;
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	default:
5787c478bd9Sstevel@tonic-gate 		logerr("phyint_group_chstate: invalid group state %d; "
5797c478bd9Sstevel@tonic-gate 		    "aborting\n", state);
5807c478bd9Sstevel@tonic-gate 		abort();
5817c478bd9Sstevel@tonic-gate 	}
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	pg->pg_sig++;
5847c478bd9Sstevel@tonic-gate 	(void) phyint_group_state_event(pg);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate  * Create a new phyint instance and initialize it from the values supplied by
5897c478bd9Sstevel@tonic-gate  * the kernel. Always check for ENXIO before logging any error, because the
5907c478bd9Sstevel@tonic-gate  * interface could have vanished after completion of SIOCGLIFCONF.
5917c478bd9Sstevel@tonic-gate  * Return values:
5927c478bd9Sstevel@tonic-gate  *	pointer to the phyint instance on success
5937c478bd9Sstevel@tonic-gate  *	NULL on failure Eg. if the phyint instance is not found in the kernel
5947c478bd9Sstevel@tonic-gate  */
5957c478bd9Sstevel@tonic-gate struct phyint_instance *
phyint_inst_init_from_k(int af,char * pi_name)5967c478bd9Sstevel@tonic-gate phyint_inst_init_from_k(int af, char *pi_name)
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	char	pg_name[LIFNAMSIZ + 1];
5997c478bd9Sstevel@tonic-gate 	int	ifsock;
6007c478bd9Sstevel@tonic-gate 	uint_t	ifindex;
6017c478bd9Sstevel@tonic-gate 	uint64_t	flags;
6027c478bd9Sstevel@tonic-gate 	struct lifreq	lifr;
6037c478bd9Sstevel@tonic-gate 	struct phyint	*pi;
6047c478bd9Sstevel@tonic-gate 	struct phyint_instance	*pii;
6057c478bd9Sstevel@tonic-gate 	boolean_t	pi_created;
6067c478bd9Sstevel@tonic-gate 	struct phyint_group	*pg;
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate retry:
6097c478bd9Sstevel@tonic-gate 	pii = NULL;
6107c478bd9Sstevel@tonic-gate 	pi = NULL;
6117c478bd9Sstevel@tonic-gate 	pg = NULL;
6127c478bd9Sstevel@tonic-gate 	pi_created = _B_FALSE;
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
6157c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_init_from_k(%s %s)\n",
6167c478bd9Sstevel@tonic-gate 		    AF_STR(af), pi_name);
6177c478bd9Sstevel@tonic-gate 	}
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	assert(af == AF_INET || af == AF_INET6);
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	/* Get the socket for doing ioctls */
6227c478bd9Sstevel@tonic-gate 	ifsock = (af == AF_INET) ? ifsock_v4 : ifsock_v6;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	/*
625e11c3f44Smeem 	 * Get the interface flags.  Ignore virtual interfaces, IPMP
626e11c3f44Smeem 	 * meta-interfaces, point-to-point interfaces, and interfaces
627e11c3f44Smeem 	 * that can't support multicast.
6287c478bd9Sstevel@tonic-gate 	 */
629e11c3f44Smeem 	(void) strlcpy(lifr.lifr_name, pi_name, sizeof (lifr.lifr_name));
6307c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
6317c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
6327c478bd9Sstevel@tonic-gate 			logperror("phyint_inst_init_from_k:"
6337c478bd9Sstevel@tonic-gate 			    " ioctl (get flags)");
6347c478bd9Sstevel@tonic-gate 		}
6357c478bd9Sstevel@tonic-gate 		return (NULL);
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate 	flags = lifr.lifr_flags;
638e11c3f44Smeem 	if (!(flags & IFF_MULTICAST) ||
639e11c3f44Smeem 	    (flags & (IFF_VIRTUAL|IFF_IPMP|IFF_POINTOPOINT)))
6407c478bd9Sstevel@tonic-gate 		return (NULL);
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	/*
6437c478bd9Sstevel@tonic-gate 	 * Get the ifindex for recording later in our tables, in case we need
6447c478bd9Sstevel@tonic-gate 	 * to create a new phyint.
6457c478bd9Sstevel@tonic-gate 	 */
6467c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFINDEX, (char *)&lifr) < 0) {
6477c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
6487c478bd9Sstevel@tonic-gate 			logperror("phyint_inst_init_from_k: "
6497c478bd9Sstevel@tonic-gate 			    " ioctl (get lifindex)");
6507c478bd9Sstevel@tonic-gate 		}
6517c478bd9Sstevel@tonic-gate 		return (NULL);
6527c478bd9Sstevel@tonic-gate 	}
6537c478bd9Sstevel@tonic-gate 	ifindex = lifr.lifr_index;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/*
6567c478bd9Sstevel@tonic-gate 	 * Get the phyint group name of this phyint, from the kernel.
6577c478bd9Sstevel@tonic-gate 	 */
6587c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFGROUPNAME, (char *)&lifr) < 0) {
6597c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
6607c478bd9Sstevel@tonic-gate 			logperror("phyint_inst_init_from_k: "
6617c478bd9Sstevel@tonic-gate 			    "ioctl (get group name)");
6627c478bd9Sstevel@tonic-gate 		}
6637c478bd9Sstevel@tonic-gate 		return (NULL);
6647c478bd9Sstevel@tonic-gate 	}
665e11c3f44Smeem 	(void) strlcpy(pg_name, lifr.lifr_groupname, sizeof (pg_name));
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	/*
6687c478bd9Sstevel@tonic-gate 	 * If the phyint is not part of any group, pg_name is the
6697c478bd9Sstevel@tonic-gate 	 * null string. If 'track_all_phyints' is false, there is no
6707c478bd9Sstevel@tonic-gate 	 * need to create a phyint.
6717c478bd9Sstevel@tonic-gate 	 */
6727c478bd9Sstevel@tonic-gate 	if (pg_name[0] == '\0' && !track_all_phyints) {
6737c478bd9Sstevel@tonic-gate 		/*
674e11c3f44Smeem 		 * If the IFF_FAILED, IFF_INACTIVE, or IFF_OFFLINE flags are
675e11c3f44Smeem 		 * set, reset them. These flags shouldn't be set if in.mpathd
676e11c3f44Smeem 		 * isn't tracking the interface.
6777c478bd9Sstevel@tonic-gate 		 */
678e11c3f44Smeem 		if ((flags & (IFF_FAILED | IFF_INACTIVE | IFF_OFFLINE))) {
679e11c3f44Smeem 			lifr.lifr_flags = flags &
680e11c3f44Smeem 			    ~(IFF_FAILED | IFF_INACTIVE | IFF_OFFLINE);
6817c478bd9Sstevel@tonic-gate 			if (ioctl(ifsock, SIOCSLIFFLAGS, (char *)&lifr) < 0) {
6827c478bd9Sstevel@tonic-gate 				if (errno != ENXIO) {
6837c478bd9Sstevel@tonic-gate 					logperror("phyint_inst_init_from_k:"
6847c478bd9Sstevel@tonic-gate 					    " ioctl (set flags)");
6857c478bd9Sstevel@tonic-gate 				}
6867c478bd9Sstevel@tonic-gate 			}
6877c478bd9Sstevel@tonic-gate 		}
6887c478bd9Sstevel@tonic-gate 		return (NULL);
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	/*
692e11c3f44Smeem 	 * We need to create a new phyint instance.  We may also need to
693e11c3f44Smeem 	 * create the group if e.g. the SIOCGLIFCONF loop in initifs() found
694e11c3f44Smeem 	 * an underlying interface before it found its IPMP meta-interface.
695e11c3f44Smeem 	 * Note that we keep any created groups even if phyint_inst_from_k()
696e11c3f44Smeem 	 * fails since a group's existence is not dependent on the ability of
697e11c3f44Smeem 	 * in.mpathd to the track the group's interfaces.
6987c478bd9Sstevel@tonic-gate 	 */
699e11c3f44Smeem 	if ((pg = phyint_group_lookup(pg_name)) == NULL) {
700e11c3f44Smeem 		if ((pg = phyint_group_create(pg_name)) == NULL) {
701e11c3f44Smeem 			logerr("phyint_inst_init_from_k: cannot create group "
702e11c3f44Smeem 			    "%s\n", pg_name);
7037c478bd9Sstevel@tonic-gate 			return (NULL);
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 		phyint_group_insert(pg);
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	/*
7097c478bd9Sstevel@tonic-gate 	 * Lookup the phyint. If the phyint does not exist create it.
7107c478bd9Sstevel@tonic-gate 	 */
7117c478bd9Sstevel@tonic-gate 	pi = phyint_lookup(pi_name);
7127c478bd9Sstevel@tonic-gate 	if (pi == NULL) {
7137c478bd9Sstevel@tonic-gate 		pi = phyint_create(pi_name, pg, ifindex, flags);
7147c478bd9Sstevel@tonic-gate 		if (pi == NULL) {
7157c478bd9Sstevel@tonic-gate 			logerr("phyint_inst_init_from_k:"
7167c478bd9Sstevel@tonic-gate 			    " unable to create phyint %s\n", pi_name);
7177c478bd9Sstevel@tonic-gate 			return (NULL);
7187c478bd9Sstevel@tonic-gate 		}
7197c478bd9Sstevel@tonic-gate 		pi_created = _B_TRUE;
7207c478bd9Sstevel@tonic-gate 	} else {
7217c478bd9Sstevel@tonic-gate 		/* The phyint exists already. */
7227c478bd9Sstevel@tonic-gate 		assert(pi_created == _B_FALSE);
7237c478bd9Sstevel@tonic-gate 		/*
7247c478bd9Sstevel@tonic-gate 		 * Normally we should see consistent values for the IPv4 and
7257c478bd9Sstevel@tonic-gate 		 * IPv6 instances, for phyint properties. If we don't, it
7267c478bd9Sstevel@tonic-gate 		 * means things have changed underneath us, and we should
7277c478bd9Sstevel@tonic-gate 		 * resync our tables with the kernel. Check whether the
7287c478bd9Sstevel@tonic-gate 		 * interface index has changed. If so, it is most likely
7297c478bd9Sstevel@tonic-gate 		 * the interface has been unplumbed and replumbed,
7307c478bd9Sstevel@tonic-gate 		 * while we are yet to update our tables. Do it now.
7317c478bd9Sstevel@tonic-gate 		 */
7327c478bd9Sstevel@tonic-gate 		if (pi->pi_ifindex != ifindex) {
7337c478bd9Sstevel@tonic-gate 			phyint_inst_delete(PHYINT_INSTANCE(pi, AF_OTHER(af)));
7347c478bd9Sstevel@tonic-gate 			goto retry;
7357c478bd9Sstevel@tonic-gate 		}
7367c478bd9Sstevel@tonic-gate 		assert(PHYINT_INSTANCE(pi, af) == NULL);
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 		/*
7397c478bd9Sstevel@tonic-gate 		 * If the group name seen by the IPv4 and IPv6 instances
7407c478bd9Sstevel@tonic-gate 		 * are different, it is most likely the groupname has
7417c478bd9Sstevel@tonic-gate 		 * changed, while we are yet to update our tables. Do it now.
7427c478bd9Sstevel@tonic-gate 		 */
7437c478bd9Sstevel@tonic-gate 		if (strcmp(pi->pi_group->pg_name, pg_name) != 0) {
7447c478bd9Sstevel@tonic-gate 			phyint_inst_delete(PHYINT_INSTANCE(pi,
7457c478bd9Sstevel@tonic-gate 			    AF_OTHER(af)));
7467c478bd9Sstevel@tonic-gate 			goto retry;
7477c478bd9Sstevel@tonic-gate 		}
7487c478bd9Sstevel@tonic-gate 	}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	/*
7517c478bd9Sstevel@tonic-gate 	 * Create a new phyint instance, corresponding to the 'af'
7527c478bd9Sstevel@tonic-gate 	 * passed in.
7537c478bd9Sstevel@tonic-gate 	 */
7547c478bd9Sstevel@tonic-gate 	pii = phyint_inst_create(pi, af);
7557c478bd9Sstevel@tonic-gate 	if (pii == NULL) {
7567c478bd9Sstevel@tonic-gate 		logerr("phyint_inst_init_from_k: unable to create"
7577c478bd9Sstevel@tonic-gate 		    "phyint inst %s\n", pi->pi_name);
758e11c3f44Smeem 		if (pi_created)
759e11c3f44Smeem 			phyint_delete(pi);
760e11c3f44Smeem 
761e11c3f44Smeem 		return (NULL);
762e11c3f44Smeem 	}
763e11c3f44Smeem 
764*9bea6098Smeem 	/*
765*9bea6098Smeem 	 * NOTE: the change_pif_flags() implementation requires a phyint
766*9bea6098Smeem 	 * instance before it can function, so a number of tasks that would
767*9bea6098Smeem 	 * otherwise be done in phyint_create() are deferred to here.
768*9bea6098Smeem 	 */
7697c478bd9Sstevel@tonic-gate 	if (pi_created) {
7707c478bd9Sstevel@tonic-gate 		/*
771*9bea6098Smeem 		 * If the interface is offline, set the state to PI_OFFLINE.
772*9bea6098Smeem 		 * Otherwise, optimistically consider this interface running.
773*9bea6098Smeem 		 * Later (in process_link_state_changes()), we will adjust
774*9bea6098Smeem 		 * this to match the current state of the link.  Further, if
775*9bea6098Smeem 		 * test addresses are subsequently assigned, we will
776*9bea6098Smeem 		 * transition to PI_NOTARGETS and then to either PI_RUNNING or
777*9bea6098Smeem 		 * PI_FAILED depending on the probe results.
778*9bea6098Smeem 		 */
779*9bea6098Smeem 		if (pi->pi_flags & IFF_OFFLINE) {
780*9bea6098Smeem 			phyint_chstate(pi, PI_OFFLINE);
781*9bea6098Smeem 		} else {
782*9bea6098Smeem 			/* calls phyint_chstate() */
783*9bea6098Smeem 			phyint_transition_to_running(pi);
784*9bea6098Smeem 		}
785*9bea6098Smeem 
786*9bea6098Smeem 		/*
787*9bea6098Smeem 		 * If this a standby phyint, determine whether it should be
788*9bea6098Smeem 		 * IFF_INACTIVE.
789*9bea6098Smeem 		 */
790*9bea6098Smeem 		if (pi->pi_flags & IFF_STANDBY)
791*9bea6098Smeem 			phyint_standby_refresh_inactive(pi);
792*9bea6098Smeem 
793*9bea6098Smeem 		/*
794e11c3f44Smeem 		 * If this phyint does not have a unique hardware address in its
795*9bea6098Smeem 		 * group, offline it.
7967c478bd9Sstevel@tonic-gate 		 */
797e11c3f44Smeem 		if (phyint_lookup_hwaddr(pi, _B_TRUE) != NULL) {
798e11c3f44Smeem 			pi->pi_hwaddrdup = _B_TRUE;
799e11c3f44Smeem 			(void) phyint_offline(pi, 0);
8007c478bd9Sstevel@tonic-gate 		}
8017c478bd9Sstevel@tonic-gate 	}
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	return (pii);
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate /*
807921e7e07Smeem  * Bind pii_probe_sock to the address associated with pii_probe_logint.
808921e7e07Smeem  * This socket will be used for sending and receiving ICMP/ICMPv6 probes to
809921e7e07Smeem  * targets. Do the common part in this function, and complete the
810921e7e07Smeem  * initializations by calling the protocol specific functions
8117c478bd9Sstevel@tonic-gate  * phyint_inst_v{4,6}_sockinit() respectively.
8127c478bd9Sstevel@tonic-gate  *
8137c478bd9Sstevel@tonic-gate  * Return values: _B_TRUE/_B_FALSE for success or failure respectively.
8147c478bd9Sstevel@tonic-gate  */
8157c478bd9Sstevel@tonic-gate boolean_t
phyint_inst_sockinit(struct phyint_instance * pii)8167c478bd9Sstevel@tonic-gate phyint_inst_sockinit(struct phyint_instance *pii)
8177c478bd9Sstevel@tonic-gate {
8187c478bd9Sstevel@tonic-gate 	boolean_t success;
8197c478bd9Sstevel@tonic-gate 	struct phyint_group *pg;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
8227c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_sockinit(%s %s)\n",
8237c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name);
8247c478bd9Sstevel@tonic-gate 	}
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	assert(pii->pii_probe_logint != NULL);
8277c478bd9Sstevel@tonic-gate 	assert(pii->pii_probe_logint->li_flags & IFF_UP);
828921e7e07Smeem 	assert(pii->pii_probe_logint->li_flags & IFF_NOFAILOVER);
8297c478bd9Sstevel@tonic-gate 	assert(pii->pii_af == AF_INET || pii->pii_af == AF_INET6);
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	/*
8327c478bd9Sstevel@tonic-gate 	 * If the socket is already bound, close pii_probe_sock
8337c478bd9Sstevel@tonic-gate 	 */
8347c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock != -1)
8357c478bd9Sstevel@tonic-gate 		close_probe_socket(pii, _B_TRUE);
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	/*
8387c478bd9Sstevel@tonic-gate 	 * If the phyint is not part of a named group and track_all_phyints is
8397c478bd9Sstevel@tonic-gate 	 * false, simply return.
8407c478bd9Sstevel@tonic-gate 	 */
8417c478bd9Sstevel@tonic-gate 	pg = pii->pii_phyint->pi_group;
8427c478bd9Sstevel@tonic-gate 	if (pg == phyint_anongroup && !track_all_phyints) {
8437c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT)
8447c478bd9Sstevel@tonic-gate 			logdebug("phyint_inst_sockinit: no group\n");
8457c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
8467c478bd9Sstevel@tonic-gate 	}
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	/*
8497c478bd9Sstevel@tonic-gate 	 * Initialize the socket by calling the protocol specific function.
8507c478bd9Sstevel@tonic-gate 	 * If it succeeds, add the socket to the poll list.
8517c478bd9Sstevel@tonic-gate 	 */
8527c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET6)
8537c478bd9Sstevel@tonic-gate 		success = phyint_inst_v6_sockinit(pii);
8547c478bd9Sstevel@tonic-gate 	else
8557c478bd9Sstevel@tonic-gate 		success = phyint_inst_v4_sockinit(pii);
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	if (success && (poll_add(pii->pii_probe_sock) == 0))
8587c478bd9Sstevel@tonic-gate 		return (_B_TRUE);
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	/* Something failed, cleanup and return false */
8617c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock != -1)
8627c478bd9Sstevel@tonic-gate 		close_probe_socket(pii, _B_FALSE);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	return (_B_FALSE);
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate /*
8687c478bd9Sstevel@tonic-gate  * IPv6 specific part in initializing the pii_probe_sock. This socket is
8697c478bd9Sstevel@tonic-gate  * used to send/receive ICMPv6 probe packets.
8707c478bd9Sstevel@tonic-gate  */
8717c478bd9Sstevel@tonic-gate static boolean_t
phyint_inst_v6_sockinit(struct phyint_instance * pii)8727c478bd9Sstevel@tonic-gate phyint_inst_v6_sockinit(struct phyint_instance *pii)
8737c478bd9Sstevel@tonic-gate {
8747c478bd9Sstevel@tonic-gate 	icmp6_filter_t filter;
8757c478bd9Sstevel@tonic-gate 	int hopcount = 1;
876e11c3f44Smeem 	int off = 0;
877e11c3f44Smeem 	int on = 1;
8787c478bd9Sstevel@tonic-gate 	struct	sockaddr_in6	testaddr;
879b6bc5f8fSGeorge Shepherd 	int flags;
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	/*
8827c478bd9Sstevel@tonic-gate 	 * Open a raw socket with ICMPv6 protocol.
8837c478bd9Sstevel@tonic-gate 	 *
884e11c3f44Smeem 	 * Use IPV6_BOUND_IF to make sure that probes are sent and received on
885e11c3f44Smeem 	 * the specified phyint only.  Bind to the test address to ensure that
886e11c3f44Smeem 	 * the responses are sent to the specified phyint.
8877c478bd9Sstevel@tonic-gate 	 *
8887c478bd9Sstevel@tonic-gate 	 * Set the hopcount to 1 so that probe packets are not routed.
8897c478bd9Sstevel@tonic-gate 	 * Disable multicast loopback. Set the receive filter to
8907c478bd9Sstevel@tonic-gate 	 * receive only ICMPv6 echo replies.
8917c478bd9Sstevel@tonic-gate 	 */
8927c478bd9Sstevel@tonic-gate 	pii->pii_probe_sock = socket(pii->pii_af, SOCK_RAW, IPPROTO_ICMPV6);
8937c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock < 0) {
8947c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: socket");
8957c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 
898b6bc5f8fSGeorge Shepherd 	/*
899b6bc5f8fSGeorge Shepherd 	 * Probes must not block in case of lower layer issues.
900b6bc5f8fSGeorge Shepherd 	 */
901b6bc5f8fSGeorge Shepherd 	if ((flags = fcntl(pii->pii_probe_sock, F_GETFL, 0)) == -1) {
902b6bc5f8fSGeorge Shepherd 		logperror_pii(pii, "phyint_inst_v6_sockinit: fcntl"
903b6bc5f8fSGeorge Shepherd 		    " F_GETFL");
904b6bc5f8fSGeorge Shepherd 		return (_B_FALSE);
905b6bc5f8fSGeorge Shepherd 	}
906b6bc5f8fSGeorge Shepherd 	if (fcntl(pii->pii_probe_sock, F_SETFL,
907b6bc5f8fSGeorge Shepherd 	    flags | O_NONBLOCK) == -1) {
908b6bc5f8fSGeorge Shepherd 		logperror_pii(pii, "phyint_inst_v6_sockinit: fcntl"
909b6bc5f8fSGeorge Shepherd 		    " F_SETFL O_NONBLOCK");
910b6bc5f8fSGeorge Shepherd 		return (_B_FALSE);
911b6bc5f8fSGeorge Shepherd 	}
912b6bc5f8fSGeorge Shepherd 
9137c478bd9Sstevel@tonic-gate 	bzero(&testaddr, sizeof (testaddr));
9147c478bd9Sstevel@tonic-gate 	testaddr.sin6_family = AF_INET6;
9157c478bd9Sstevel@tonic-gate 	testaddr.sin6_port = 0;
9167c478bd9Sstevel@tonic-gate 	testaddr.sin6_addr = pii->pii_probe_logint->li_addr;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	if (bind(pii->pii_probe_sock, (struct sockaddr *)&testaddr,
9197c478bd9Sstevel@tonic-gate 	    sizeof (testaddr)) < 0) {
9207c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: IPv6 bind");
9217c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
9227c478bd9Sstevel@tonic-gate 	}
9237c478bd9Sstevel@tonic-gate 
924e11c3f44Smeem 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_MULTICAST_IF,
9257c478bd9Sstevel@tonic-gate 	    (char *)&pii->pii_ifindex, sizeof (uint_t)) < 0) {
9267c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
927e11c3f44Smeem 		    " IPV6_MULTICAST_IF");
928e11c3f44Smeem 		return (_B_FALSE);
929e11c3f44Smeem 	}
930e11c3f44Smeem 
931e11c3f44Smeem 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_BOUND_IF,
932e11c3f44Smeem 	    &pii->pii_ifindex, sizeof (uint_t)) < 0) {
933e11c3f44Smeem 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
934e11c3f44Smeem 		    " IPV6_BOUND_IF");
9357c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
9367c478bd9Sstevel@tonic-gate 	}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
9397c478bd9Sstevel@tonic-gate 	    (char *)&hopcount, sizeof (hopcount)) < 0) {
9407c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
9417c478bd9Sstevel@tonic-gate 		    " IPV6_UNICAST_HOPS");
9427c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
9437c478bd9Sstevel@tonic-gate 	}
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
9467c478bd9Sstevel@tonic-gate 	    (char *)&hopcount, sizeof (hopcount)) < 0) {
9477c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
9487c478bd9Sstevel@tonic-gate 		    " IPV6_MULTICAST_HOPS");
9497c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
9507c478bd9Sstevel@tonic-gate 	}
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
953e11c3f44Smeem 	    (char *)&off, sizeof (off)) < 0) {
9547c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
9557c478bd9Sstevel@tonic-gate 		    " IPV6_MULTICAST_LOOP");
9567c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
9577c478bd9Sstevel@tonic-gate 	}
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	/*
9607c478bd9Sstevel@tonic-gate 	 * Filter out so that we only receive ICMP echo replies
9617c478bd9Sstevel@tonic-gate 	 */
9627c478bd9Sstevel@tonic-gate 	ICMP6_FILTER_SETBLOCKALL(&filter);
9637c478bd9Sstevel@tonic-gate 	ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_ICMPV6, ICMP6_FILTER,
9667c478bd9Sstevel@tonic-gate 	    (char *)&filter, sizeof (filter)) < 0) {
9677c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
9687c478bd9Sstevel@tonic-gate 		    " ICMP6_FILTER");
9697c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 
972e11c3f44Smeem 	/* Enable receipt of hoplimit */
9737c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
974e11c3f44Smeem 	    &on, sizeof (on)) < 0) {
9757c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
9767c478bd9Sstevel@tonic-gate 		    " IPV6_RECVHOPLIMIT");
9777c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
9787c478bd9Sstevel@tonic-gate 	}
9797c478bd9Sstevel@tonic-gate 
980e11c3f44Smeem 	/* Enable receipt of timestamp */
981e11c3f44Smeem 	if (setsockopt(pii->pii_probe_sock, SOL_SOCKET, SO_TIMESTAMP,
982e11c3f44Smeem 	    &on, sizeof (on)) < 0) {
983e11c3f44Smeem 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
984e11c3f44Smeem 		    " SO_TIMESTAMP");
985e11c3f44Smeem 		return (_B_FALSE);
986e11c3f44Smeem 	}
987e11c3f44Smeem 
9887c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate /*
9927c478bd9Sstevel@tonic-gate  * IPv4 specific part in initializing the pii_probe_sock. This socket is
9937c478bd9Sstevel@tonic-gate  * used to send/receive ICMPv4 probe packets.
9947c478bd9Sstevel@tonic-gate  */
9957c478bd9Sstevel@tonic-gate static boolean_t
phyint_inst_v4_sockinit(struct phyint_instance * pii)9967c478bd9Sstevel@tonic-gate phyint_inst_v4_sockinit(struct phyint_instance *pii)
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	struct sockaddr_in  testaddr;
999e11c3f44Smeem 	char	char_off = 0;
10007c478bd9Sstevel@tonic-gate 	int	ttl = 1;
10017c478bd9Sstevel@tonic-gate 	char	char_ttl = 1;
1002e11c3f44Smeem 	int	on = 1;
1003b6bc5f8fSGeorge Shepherd 	int	flags;
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	/*
10067c478bd9Sstevel@tonic-gate 	 * Open a raw socket with ICMPv4 protocol.
10077c478bd9Sstevel@tonic-gate 	 *
1008e11c3f44Smeem 	 * Use IP_BOUND_IF to make sure that probes are sent and received on
1009e11c3f44Smeem 	 * the specified phyint only.  Bind to the test address to ensure that
1010e11c3f44Smeem 	 * the responses are sent to the specified phyint.
10117c478bd9Sstevel@tonic-gate 	 *
10127c478bd9Sstevel@tonic-gate 	 * Set the ttl to 1 so that probe packets are not routed.
1013e11c3f44Smeem 	 * Disable multicast loopback.  Enable receipt of timestamp.
10147c478bd9Sstevel@tonic-gate 	 */
10157c478bd9Sstevel@tonic-gate 	pii->pii_probe_sock = socket(pii->pii_af, SOCK_RAW, IPPROTO_ICMP);
10167c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock < 0) {
10177c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: socket");
10187c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
10197c478bd9Sstevel@tonic-gate 	}
10207c478bd9Sstevel@tonic-gate 
1021b6bc5f8fSGeorge Shepherd 	/*
1022b6bc5f8fSGeorge Shepherd 	 * Probes must not block in case of lower layer issues.
1023b6bc5f8fSGeorge Shepherd 	 */
1024b6bc5f8fSGeorge Shepherd 	if ((flags = fcntl(pii->pii_probe_sock, F_GETFL, 0)) == -1) {
1025b6bc5f8fSGeorge Shepherd 		logperror_pii(pii, "phyint_inst_v4_sockinit: fcntl"
1026b6bc5f8fSGeorge Shepherd 		    " F_GETFL");
1027b6bc5f8fSGeorge Shepherd 		return (_B_FALSE);
1028b6bc5f8fSGeorge Shepherd 	}
1029b6bc5f8fSGeorge Shepherd 	if (fcntl(pii->pii_probe_sock, F_SETFL,
1030b6bc5f8fSGeorge Shepherd 	    flags | O_NONBLOCK) == -1) {
1031b6bc5f8fSGeorge Shepherd 		logperror_pii(pii, "phyint_inst_v4_sockinit: fcntl"
1032b6bc5f8fSGeorge Shepherd 		    " F_SETFL O_NONBLOCK");
1033b6bc5f8fSGeorge Shepherd 		return (_B_FALSE);
1034b6bc5f8fSGeorge Shepherd 	}
1035b6bc5f8fSGeorge Shepherd 
10367c478bd9Sstevel@tonic-gate 	bzero(&testaddr, sizeof (testaddr));
10377c478bd9Sstevel@tonic-gate 	testaddr.sin_family = AF_INET;
10387c478bd9Sstevel@tonic-gate 	testaddr.sin_port = 0;
10397c478bd9Sstevel@tonic-gate 	IN6_V4MAPPED_TO_INADDR(&pii->pii_probe_logint->li_addr,
10407c478bd9Sstevel@tonic-gate 	    &testaddr.sin_addr);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	if (bind(pii->pii_probe_sock, (struct sockaddr *)&testaddr,
10437c478bd9Sstevel@tonic-gate 	    sizeof (testaddr)) < 0) {
10447c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: IPv4 bind");
10457c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
10467c478bd9Sstevel@tonic-gate 	}
10477c478bd9Sstevel@tonic-gate 
1048e11c3f44Smeem 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_BOUND_IF,
1049e11c3f44Smeem 	    &pii->pii_ifindex, sizeof (uint_t)) < 0) {
1050e11c3f44Smeem 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
1051e11c3f44Smeem 		    " IP_BOUND_IF");
1052e11c3f44Smeem 		return (_B_FALSE);
1053e11c3f44Smeem 	}
1054e11c3f44Smeem 
1055e11c3f44Smeem 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_MULTICAST_IF,
10567c478bd9Sstevel@tonic-gate 	    (char *)&testaddr.sin_addr, sizeof (struct in_addr)) < 0) {
10577c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
1058e11c3f44Smeem 		    " IP_MULTICAST_IF");
10597c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
10607c478bd9Sstevel@tonic-gate 	}
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_TTL,
10637c478bd9Sstevel@tonic-gate 	    (char *)&ttl, sizeof (ttl)) < 0) {
10647c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
10657c478bd9Sstevel@tonic-gate 		    " IP_TTL");
10667c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
10677c478bd9Sstevel@tonic-gate 	}
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
1070e11c3f44Smeem 	    (char *)&char_off, sizeof (char_off)) == -1) {
10717c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
10727c478bd9Sstevel@tonic-gate 		    " IP_MULTICAST_LOOP");
10737c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_MULTICAST_TTL,
10777c478bd9Sstevel@tonic-gate 	    (char *)&char_ttl, sizeof (char_ttl)) == -1) {
10787c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
10797c478bd9Sstevel@tonic-gate 		    " IP_MULTICAST_TTL");
10807c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
10817c478bd9Sstevel@tonic-gate 	}
10827c478bd9Sstevel@tonic-gate 
1083e11c3f44Smeem 	if (setsockopt(pii->pii_probe_sock, SOL_SOCKET, SO_TIMESTAMP, &on,
1084e11c3f44Smeem 	    sizeof (on)) < 0) {
1085e11c3f44Smeem 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
1086e11c3f44Smeem 		    " SO_TIMESTAMP");
1087e11c3f44Smeem 		return (_B_FALSE);
1088e11c3f44Smeem 	}
1089e11c3f44Smeem 
10907c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
10917c478bd9Sstevel@tonic-gate }
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate /*
10947c478bd9Sstevel@tonic-gate  * Remove the phyint group from the list of 'all phyint groups'
10957c478bd9Sstevel@tonic-gate  * and free it.
10967c478bd9Sstevel@tonic-gate  */
1097e11c3f44Smeem void
phyint_group_delete(struct phyint_group * pg)10987c478bd9Sstevel@tonic-gate phyint_group_delete(struct phyint_group *pg)
10997c478bd9Sstevel@tonic-gate {
11007c478bd9Sstevel@tonic-gate 	/*
11017c478bd9Sstevel@tonic-gate 	 * The anonymous group always exists, even when empty.
11027c478bd9Sstevel@tonic-gate 	 */
11037c478bd9Sstevel@tonic-gate 	if (pg == phyint_anongroup)
11047c478bd9Sstevel@tonic-gate 		return;
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
11077c478bd9Sstevel@tonic-gate 		logdebug("phyint_group_delete('%s')\n", pg->pg_name);
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	/*
11107c478bd9Sstevel@tonic-gate 	 * The phyint group must be empty, and must not have any phyints.
11117c478bd9Sstevel@tonic-gate 	 * The phyint group must be in the list of all phyint groups
11127c478bd9Sstevel@tonic-gate 	 */
11137c478bd9Sstevel@tonic-gate 	assert(pg->pg_phyint == NULL);
11147c478bd9Sstevel@tonic-gate 	assert(phyint_groups == pg || pg->pg_prev != NULL);
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	if (pg->pg_prev != NULL)
11177c478bd9Sstevel@tonic-gate 		pg->pg_prev->pg_next = pg->pg_next;
11187c478bd9Sstevel@tonic-gate 	else
11197c478bd9Sstevel@tonic-gate 		phyint_groups = pg->pg_next;
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	if (pg->pg_next != NULL)
11227c478bd9Sstevel@tonic-gate 		pg->pg_next->pg_prev = pg->pg_prev;
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	pg->pg_next = NULL;
11257c478bd9Sstevel@tonic-gate 	pg->pg_prev = NULL;
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	phyint_grouplistsig++;
11287c478bd9Sstevel@tonic-gate 	(void) phyint_group_change_event(pg, IPMP_GROUP_REMOVE);
11297c478bd9Sstevel@tonic-gate 
1130e11c3f44Smeem 	addrlist_free(&pg->pg_addrs);
11317c478bd9Sstevel@tonic-gate 	free(pg);
11327c478bd9Sstevel@tonic-gate }
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate /*
1135e11c3f44Smeem  * Refresh the state of `pg' based on its current members.
1136e11c3f44Smeem  */
1137e11c3f44Smeem void
phyint_group_refresh_state(struct phyint_group * pg)1138e11c3f44Smeem phyint_group_refresh_state(struct phyint_group *pg)
1139e11c3f44Smeem {
1140e11c3f44Smeem 	enum pg_state state;
1141e11c3f44Smeem 	enum pg_state origstate = pg->pg_state;
1142e11c3f44Smeem 	struct phyint *pi, *usablepi;
1143e11c3f44Smeem 	uint_t nif = 0, nusable = 0;
1144e11c3f44Smeem 
1145e11c3f44Smeem 	/*
1146e11c3f44Smeem 	 * Anonymous groups never change state.
1147e11c3f44Smeem 	 */
1148e11c3f44Smeem 	if (pg == phyint_anongroup)
1149e11c3f44Smeem 		return;
1150e11c3f44Smeem 
1151e11c3f44Smeem 	for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext) {
1152e11c3f44Smeem 		nif++;
1153e11c3f44Smeem 		if (phyint_is_usable(pi)) {
1154e11c3f44Smeem 			nusable++;
1155e11c3f44Smeem 			usablepi = pi;
1156e11c3f44Smeem 		}
1157e11c3f44Smeem 	}
1158e11c3f44Smeem 
1159e11c3f44Smeem 	if (nusable == 0)
1160e11c3f44Smeem 		state = PG_FAILED;
1161e11c3f44Smeem 	else if (nif == nusable)
1162e11c3f44Smeem 		state = PG_OK;
1163e11c3f44Smeem 	else
1164e11c3f44Smeem 		state = PG_DEGRADED;
1165e11c3f44Smeem 
1166e11c3f44Smeem 	phyint_group_chstate(pg, state);
1167e11c3f44Smeem 
1168e11c3f44Smeem 	/*
1169e11c3f44Smeem 	 * If we're shutting down, skip logging messages since otherwise our
1170e11c3f44Smeem 	 * shutdown housecleaning will make us report that groups are unusable.
1171e11c3f44Smeem 	 */
1172e11c3f44Smeem 	if (cleanup_started)
1173e11c3f44Smeem 		return;
1174e11c3f44Smeem 
1175e11c3f44Smeem 	/*
1176e11c3f44Smeem 	 * NOTE: We use pg_failmsg_printed rather than origstate since
1177e11c3f44Smeem 	 * otherwise at startup we'll log a "now usable" message when the
1178e11c3f44Smeem 	 * first usable phyint is added to an empty group.
1179e11c3f44Smeem 	 */
1180e11c3f44Smeem 	if (state != PG_FAILED && pg->pg_failmsg_printed) {
1181e11c3f44Smeem 		assert(origstate == PG_FAILED);
1182e11c3f44Smeem 		logerr("At least 1 IP interface (%s) in group %s is now "
1183e11c3f44Smeem 		    "usable\n", usablepi->pi_name, pg->pg_name);
1184e11c3f44Smeem 		pg->pg_failmsg_printed = _B_FALSE;
1185e11c3f44Smeem 	} else if (origstate != PG_FAILED && state == PG_FAILED) {
1186e11c3f44Smeem 		logerr("All IP interfaces in group %s are now unusable\n",
1187e11c3f44Smeem 		    pg->pg_name);
1188e11c3f44Smeem 		pg->pg_failmsg_printed = _B_TRUE;
1189e11c3f44Smeem 	}
1190e11c3f44Smeem }
1191e11c3f44Smeem 
1192e11c3f44Smeem /*
11937c478bd9Sstevel@tonic-gate  * Extract information from the kernel about the desired phyint.
11947c478bd9Sstevel@tonic-gate  * Look only for properties of the phyint and not properties of logints.
11957c478bd9Sstevel@tonic-gate  * Take appropriate action on the changes.
11967c478bd9Sstevel@tonic-gate  * Return codes:
11977c478bd9Sstevel@tonic-gate  *	PI_OK
11987c478bd9Sstevel@tonic-gate  *		The phyint exists in the kernel and matches our knowledge
11997c478bd9Sstevel@tonic-gate  *		of the phyint.
12007c478bd9Sstevel@tonic-gate  *	PI_DELETED
12017c478bd9Sstevel@tonic-gate  *		The phyint has vanished in the kernel.
12027c478bd9Sstevel@tonic-gate  *	PI_IFINDEX_CHANGED
12037c478bd9Sstevel@tonic-gate  *		The phyint's interface index has changed.
12047c478bd9Sstevel@tonic-gate  *		Ask the caller to delete and recreate the phyint.
12057c478bd9Sstevel@tonic-gate  *	PI_IOCTL_ERROR
12067c478bd9Sstevel@tonic-gate  *		Some ioctl error. Don't change anything.
12077c478bd9Sstevel@tonic-gate  *	PI_GROUP_CHANGED
12087c478bd9Sstevel@tonic-gate  *		The phyint has changed group.
12097c478bd9Sstevel@tonic-gate  */
12107c478bd9Sstevel@tonic-gate int
phyint_inst_update_from_k(struct phyint_instance * pii)12117c478bd9Sstevel@tonic-gate phyint_inst_update_from_k(struct phyint_instance *pii)
12127c478bd9Sstevel@tonic-gate {
12137c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
12147c478bd9Sstevel@tonic-gate 	int	ifsock;
12157c478bd9Sstevel@tonic-gate 	struct phyint *pi;
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	pi = pii->pii_phyint;
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
12207c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_update_from_k(%s %s)\n",
12217c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pi->pi_name);
12227c478bd9Sstevel@tonic-gate 	}
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	/*
12257c478bd9Sstevel@tonic-gate 	 * Get the ifindex from the kernel, for comparison with the
12267c478bd9Sstevel@tonic-gate 	 * value in our tables.
12277c478bd9Sstevel@tonic-gate 	 */
12287c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
12297c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	ifsock = (pii->pii_af == AF_INET) ? ifsock_v4 : ifsock_v6;
12327c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFINDEX, &lifr) < 0) {
12337c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
12347c478bd9Sstevel@tonic-gate 			return (PI_DELETED);
12357c478bd9Sstevel@tonic-gate 		} else {
12367c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "phyint_inst_update_from_k:"
12377c478bd9Sstevel@tonic-gate 			    " ioctl (get lifindex)");
12387c478bd9Sstevel@tonic-gate 			return (PI_IOCTL_ERROR);
12397c478bd9Sstevel@tonic-gate 		}
12407c478bd9Sstevel@tonic-gate 	}
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	if (lifr.lifr_index != pi->pi_ifindex) {
12437c478bd9Sstevel@tonic-gate 		/*
12447c478bd9Sstevel@tonic-gate 		 * The index has changed. Most likely the interface has
12457c478bd9Sstevel@tonic-gate 		 * been unplumbed and replumbed. Ask the caller to take
12467c478bd9Sstevel@tonic-gate 		 * appropriate action.
12477c478bd9Sstevel@tonic-gate 		 */
12487c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT) {
12497c478bd9Sstevel@tonic-gate 			logdebug("phyint_inst_update_from_k:"
12507c478bd9Sstevel@tonic-gate 			    " old index %d new index %d\n",
12517c478bd9Sstevel@tonic-gate 			    pi->pi_ifindex, lifr.lifr_index);
12527c478bd9Sstevel@tonic-gate 		}
12537c478bd9Sstevel@tonic-gate 		return (PI_IFINDEX_CHANGED);
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	/*
12577c478bd9Sstevel@tonic-gate 	 * Get the group name from the kernel, for comparison with
12587c478bd9Sstevel@tonic-gate 	 * the value in our tables.
12597c478bd9Sstevel@tonic-gate 	 */
12607c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFGROUPNAME, &lifr) < 0) {
12617c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
12627c478bd9Sstevel@tonic-gate 			return (PI_DELETED);
12637c478bd9Sstevel@tonic-gate 		} else {
12647c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "phyint_inst_update_from_k:"
12657c478bd9Sstevel@tonic-gate 			    " ioctl (get groupname)");
12667c478bd9Sstevel@tonic-gate 			return (PI_IOCTL_ERROR);
12677c478bd9Sstevel@tonic-gate 		}
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	/*
12717c478bd9Sstevel@tonic-gate 	 * If the phyint has changed group i.e. if the phyint group name
12727c478bd9Sstevel@tonic-gate 	 * returned by the kernel is different, ask the caller to delete
12737c478bd9Sstevel@tonic-gate 	 * and recreate the phyint in the right group
12747c478bd9Sstevel@tonic-gate 	 */
12757c478bd9Sstevel@tonic-gate 	if (strcmp(lifr.lifr_groupname, pi->pi_group->pg_name) != 0) {
12767c478bd9Sstevel@tonic-gate 		/* Groupname has changed */
12777c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT) {
12787c478bd9Sstevel@tonic-gate 			logdebug("phyint_inst_update_from_k:"
12797c478bd9Sstevel@tonic-gate 			    " groupname change\n");
12807c478bd9Sstevel@tonic-gate 		}
12817c478bd9Sstevel@tonic-gate 		return (PI_GROUP_CHANGED);
12827c478bd9Sstevel@tonic-gate 	}
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	/*
12857c478bd9Sstevel@tonic-gate 	 * Get the current phyint flags from the kernel, and determine what
12867c478bd9Sstevel@tonic-gate 	 * flags have changed by comparing against our tables.	Note that the
12877c478bd9Sstevel@tonic-gate 	 * IFF_INACTIVE processing in initifs() relies on this call to ensure
12887c478bd9Sstevel@tonic-gate 	 * that IFF_INACTIVE is really still set on the interface.
12897c478bd9Sstevel@tonic-gate 	 */
12907c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFFLAGS, &lifr) < 0) {
12917c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
12927c478bd9Sstevel@tonic-gate 			return (PI_DELETED);
12937c478bd9Sstevel@tonic-gate 		} else {
12947c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "phyint_inst_update_from_k: "
12957c478bd9Sstevel@tonic-gate 			    " ioctl (get flags)");
12967c478bd9Sstevel@tonic-gate 			return (PI_IOCTL_ERROR);
12977c478bd9Sstevel@tonic-gate 		}
12987c478bd9Sstevel@tonic-gate 	}
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 	pi->pi_flags = PHYINT_FLAGS(lifr.lifr_flags);
13017c478bd9Sstevel@tonic-gate 	if (pi->pi_v4 != NULL)
13027c478bd9Sstevel@tonic-gate 		pi->pi_v4->pii_flags = pi->pi_flags;
13037c478bd9Sstevel@tonic-gate 	if (pi->pi_v6 != NULL)
13047c478bd9Sstevel@tonic-gate 		pi->pi_v6->pii_flags = pi->pi_flags;
13057c478bd9Sstevel@tonic-gate 
1306e11c3f44Smeem 	/*
1307e11c3f44Smeem 	 * Make sure the IFF_FAILED flag is set if and only if we think
1308e11c3f44Smeem 	 * the interface should be failed.
1309e11c3f44Smeem 	 */
13107c478bd9Sstevel@tonic-gate 	if (pi->pi_flags & IFF_FAILED) {
1311e11c3f44Smeem 		if (pi->pi_state == PI_RUNNING)
1312e11c3f44Smeem 			(void) change_pif_flags(pi, 0, IFF_FAILED);
13137c478bd9Sstevel@tonic-gate 	} else {
1314e11c3f44Smeem 		if (pi->pi_state == PI_FAILED)
1315e11c3f44Smeem 			(void) change_pif_flags(pi, IFF_FAILED, IFF_INACTIVE);
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	/* No change in phyint status */
13197c478bd9Sstevel@tonic-gate 	return (PI_OK);
13207c478bd9Sstevel@tonic-gate }
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate /*
13237c478bd9Sstevel@tonic-gate  * Delete the phyint. Remove it from the list of all phyints, and the
1324e11c3f44Smeem  * list of phyint group members.
13257c478bd9Sstevel@tonic-gate  */
13267c478bd9Sstevel@tonic-gate static void
phyint_delete(struct phyint * pi)13277c478bd9Sstevel@tonic-gate phyint_delete(struct phyint *pi)
13287c478bd9Sstevel@tonic-gate {
1329*9bea6098Smeem 	boolean_t active;
1330e11c3f44Smeem 	struct phyint *pi2;
13317c478bd9Sstevel@tonic-gate 	struct phyint_group *pg = pi->pi_group;
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
13347c478bd9Sstevel@tonic-gate 		logdebug("phyint_delete(%s)\n", pi->pi_name);
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	/* Both IPv4 and IPv6 phyint instances must have been deleted. */
13377c478bd9Sstevel@tonic-gate 	assert(pi->pi_v4 == NULL && pi->pi_v6 == NULL);
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	/*
13407c478bd9Sstevel@tonic-gate 	 * The phyint must belong to a group.
13417c478bd9Sstevel@tonic-gate 	 */
13427c478bd9Sstevel@tonic-gate 	assert(pg->pg_phyint == pi || pi->pi_pgprev != NULL);
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	/* The phyint must be in the list of all phyints */
13457c478bd9Sstevel@tonic-gate 	assert(phyints == pi || pi->pi_prev != NULL);
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	/* Remove the phyint from the phyint group list */
13487c478bd9Sstevel@tonic-gate 	pg->pg_sig++;
13497c478bd9Sstevel@tonic-gate 	(void) phyint_group_member_event(pg, pi, IPMP_IF_REMOVE);
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 	if (pi->pi_pgprev == NULL) {
13527c478bd9Sstevel@tonic-gate 		/* Phyint is the 1st in the phyint group list */
13537c478bd9Sstevel@tonic-gate 		pg->pg_phyint = pi->pi_pgnext;
13547c478bd9Sstevel@tonic-gate 	} else {
13557c478bd9Sstevel@tonic-gate 		pi->pi_pgprev->pi_pgnext = pi->pi_pgnext;
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate 	if (pi->pi_pgnext != NULL)
13587c478bd9Sstevel@tonic-gate 		pi->pi_pgnext->pi_pgprev = pi->pi_pgprev;
13597c478bd9Sstevel@tonic-gate 	pi->pi_pgnext = NULL;
13607c478bd9Sstevel@tonic-gate 	pi->pi_pgprev = NULL;
13617c478bd9Sstevel@tonic-gate 
1362e11c3f44Smeem 	/* Refresh the group state now that this phyint has been removed */
1363e11c3f44Smeem 	phyint_group_refresh_state(pg);
1364e11c3f44Smeem 
13657c478bd9Sstevel@tonic-gate 	/* Remove the phyint from the global list of phyints */
13667c478bd9Sstevel@tonic-gate 	if (pi->pi_prev == NULL) {
13677c478bd9Sstevel@tonic-gate 		/* Phyint is the 1st in the list */
13687c478bd9Sstevel@tonic-gate 		phyints = pi->pi_next;
13697c478bd9Sstevel@tonic-gate 	} else {
13707c478bd9Sstevel@tonic-gate 		pi->pi_prev->pi_next = pi->pi_next;
13717c478bd9Sstevel@tonic-gate 	}
13727c478bd9Sstevel@tonic-gate 	if (pi->pi_next != NULL)
13737c478bd9Sstevel@tonic-gate 		pi->pi_next->pi_prev = pi->pi_prev;
13747c478bd9Sstevel@tonic-gate 	pi->pi_next = NULL;
13757c478bd9Sstevel@tonic-gate 	pi->pi_prev = NULL;
13767c478bd9Sstevel@tonic-gate 
1377e11c3f44Smeem 	/*
1378e11c3f44Smeem 	 * See if another phyint in the group had been offlined because
1379e11c3f44Smeem 	 * it was a dup of `pi' -- and if so, online it.
1380e11c3f44Smeem 	 */
1381e11c3f44Smeem 	if (!pi->pi_hwaddrdup &&
1382e11c3f44Smeem 	    (pi2 = phyint_lookup_hwaddr(pi, _B_FALSE)) != NULL) {
1383e11c3f44Smeem 		assert(pi2->pi_hwaddrdup);
1384e11c3f44Smeem 		(void) phyint_undo_offline(pi2);
1385e11c3f44Smeem 	}
1386*9bea6098Smeem 
1387*9bea6098Smeem 	/*
1388*9bea6098Smeem 	 * If the interface was in a named group and was either an active
1389*9bea6098Smeem 	 * standby or the last active interface, try to activate another
1390*9bea6098Smeem 	 * interface to compensate.
1391*9bea6098Smeem 	 */
1392*9bea6098Smeem 	if (pg != phyint_anongroup) {
1393*9bea6098Smeem 		active = _B_FALSE;
1394*9bea6098Smeem 		for (pi2 = pg->pg_phyint; pi2 != NULL; pi2 = pi2->pi_pgnext) {
1395*9bea6098Smeem 			if (phyint_is_functioning(pi2) &&
1396*9bea6098Smeem 			    !(pi2->pi_flags & IFF_INACTIVE)) {
1397*9bea6098Smeem 				active = _B_TRUE;
1398*9bea6098Smeem 				break;
1399*9bea6098Smeem 			}
1400*9bea6098Smeem 		}
1401*9bea6098Smeem 
1402*9bea6098Smeem 		if (!active ||
1403*9bea6098Smeem 		    (pi->pi_flags & (IFF_STANDBY|IFF_INACTIVE)) == IFF_STANDBY)
1404*9bea6098Smeem 			phyint_activate_another(pi);
1405*9bea6098Smeem 	}
1406*9bea6098Smeem 
1407e11c3f44Smeem 	phyint_link_close(pi);
14087c478bd9Sstevel@tonic-gate 	free(pi);
1409e11c3f44Smeem }
14107c478bd9Sstevel@tonic-gate 
1411e11c3f44Smeem /*
1412e11c3f44Smeem  * Offline phyint `pi' if at least `minred' usable interfaces remain in the
1413e11c3f44Smeem  * group.  Returns an IPMP error code.
1414e11c3f44Smeem  */
1415e11c3f44Smeem int
phyint_offline(struct phyint * pi,uint_t minred)1416e11c3f44Smeem phyint_offline(struct phyint *pi, uint_t minred)
1417e11c3f44Smeem {
1418c445e3e1Smeem 	boolean_t was_active;
1419e11c3f44Smeem 	unsigned int nusable = 0;
1420e11c3f44Smeem 	struct phyint *pi2;
1421e11c3f44Smeem 	struct phyint_group *pg = pi->pi_group;
1422e11c3f44Smeem 
1423e11c3f44Smeem 	/*
1424e11c3f44Smeem 	 * Verify that enough usable interfaces in the group would remain.
1425e11c3f44Smeem 	 * As a special case, if the group has failed, allow any non-offline
1426e11c3f44Smeem 	 * phyints to be offlined.
1427e11c3f44Smeem 	 */
1428e11c3f44Smeem 	if (pg != phyint_anongroup) {
1429e11c3f44Smeem 		for (pi2 = pg->pg_phyint; pi2 != NULL; pi2 = pi2->pi_pgnext) {
1430e11c3f44Smeem 			if (pi2 == pi)
1431e11c3f44Smeem 				continue;
1432e11c3f44Smeem 			if (phyint_is_usable(pi2) ||
1433e11c3f44Smeem 			    (GROUP_FAILED(pg) && pi2->pi_state != PI_OFFLINE))
1434e11c3f44Smeem 				nusable++;
1435e11c3f44Smeem 		}
1436e11c3f44Smeem 	}
1437e11c3f44Smeem 	if (nusable < minred)
1438e11c3f44Smeem 		return (IPMP_EMINRED);
1439e11c3f44Smeem 
1440c445e3e1Smeem 	was_active = ((pi->pi_flags & IFF_INACTIVE) == 0);
1441c445e3e1Smeem 
1442c445e3e1Smeem 	if (!change_pif_flags(pi, IFF_OFFLINE, IFF_INACTIVE))
1443e11c3f44Smeem 		return (IPMP_FAILURE);
1444e11c3f44Smeem 
1445e11c3f44Smeem 	/*
1446e11c3f44Smeem 	 * The interface is now offline, so stop probing it.  Note that
1447e11c3f44Smeem 	 * if_mpadm(1M) will down the test addresses, after receiving a
1448e11c3f44Smeem 	 * success reply from us. The routing socket message will then make us
1449e11c3f44Smeem 	 * close the socket used for sending probes. But it is more logical
1450e11c3f44Smeem 	 * that an offlined interface must not be probed, even if it has test
1451e11c3f44Smeem 	 * addresses.
1452e11c3f44Smeem 	 *
1453e11c3f44Smeem 	 * NOTE: stop_probing() also sets PI_OFFLINE.
1454e11c3f44Smeem 	 */
1455e11c3f44Smeem 	stop_probing(pi);
1456e11c3f44Smeem 
1457e11c3f44Smeem 	/*
1458e11c3f44Smeem 	 * If we're offlining the phyint because it has a duplicate hardware
1459e11c3f44Smeem 	 * address, print a warning -- and leave the link open so that we can
1460e11c3f44Smeem 	 * be notified of hardware address changes that make it usable again.
1461e11c3f44Smeem 	 * Otherwise, close the link so that we won't prevent a detach.
1462e11c3f44Smeem 	 */
1463e11c3f44Smeem 	if (pi->pi_hwaddrdup) {
1464e11c3f44Smeem 		logerr("IP interface %s has a hardware address which is not "
1465e11c3f44Smeem 		    "unique in group %s; offlining\n", pi->pi_name,
1466e11c3f44Smeem 		    pg->pg_name);
1467e11c3f44Smeem 	} else {
1468e11c3f44Smeem 		phyint_link_close(pi);
1469e11c3f44Smeem 	}
1470e11c3f44Smeem 
1471e11c3f44Smeem 	/*
1472e11c3f44Smeem 	 * If this phyint was preventing another phyint with a duplicate
1473e11c3f44Smeem 	 * hardware address from being online, bring that one online now.
1474e11c3f44Smeem 	 */
1475e11c3f44Smeem 	if (!pi->pi_hwaddrdup &&
1476e11c3f44Smeem 	    (pi2 = phyint_lookup_hwaddr(pi, _B_FALSE)) != NULL) {
1477e11c3f44Smeem 		assert(pi2->pi_hwaddrdup);
1478e11c3f44Smeem 		(void) phyint_undo_offline(pi2);
1479e11c3f44Smeem 	}
1480e11c3f44Smeem 
1481e11c3f44Smeem 	/*
1482e11c3f44Smeem 	 * If this interface was active, try to activate another INACTIVE
1483e11c3f44Smeem 	 * interface in the group.
1484e11c3f44Smeem 	 */
1485c445e3e1Smeem 	if (was_active)
1486e11c3f44Smeem 		phyint_activate_another(pi);
1487e11c3f44Smeem 
1488e11c3f44Smeem 	return (IPMP_SUCCESS);
1489e11c3f44Smeem }
1490e11c3f44Smeem 
1491e11c3f44Smeem /*
1492e11c3f44Smeem  * Undo a previous offline of `pi'.  Returns an IPMP error code.
1493e11c3f44Smeem  */
1494e11c3f44Smeem int
phyint_undo_offline(struct phyint * pi)1495e11c3f44Smeem phyint_undo_offline(struct phyint *pi)
1496e11c3f44Smeem {
1497e11c3f44Smeem 	if (pi->pi_state != PI_OFFLINE) {
1498e11c3f44Smeem 		errno = EINVAL;
1499e11c3f44Smeem 		return (IPMP_FAILURE);
1500e11c3f44Smeem 	}
1501e11c3f44Smeem 
1502e11c3f44Smeem 	/*
1503e11c3f44Smeem 	 * If necessary, reinitialize our link information and verify that its
1504e11c3f44Smeem 	 * hardware address is still unique across the group.
1505e11c3f44Smeem 	 */
1506e11c3f44Smeem 	if (pi->pi_dh == NULL && !phyint_link_init(pi)) {
1507e11c3f44Smeem 		errno = EIO;
1508e11c3f44Smeem 		return (IPMP_FAILURE);
1509e11c3f44Smeem 	}
1510e11c3f44Smeem 
1511e11c3f44Smeem 	if (phyint_lookup_hwaddr(pi, _B_TRUE) != NULL) {
1512e11c3f44Smeem 		pi->pi_hwaddrdup = _B_TRUE;
1513e11c3f44Smeem 		return (IPMP_EHWADDRDUP);
1514e11c3f44Smeem 	}
1515e11c3f44Smeem 
1516e11c3f44Smeem 	if (pi->pi_hwaddrdup) {
1517e11c3f44Smeem 		logerr("IP interface %s now has a unique hardware address in "
1518e11c3f44Smeem 		    "group %s; onlining\n", pi->pi_name, pi->pi_group->pg_name);
1519e11c3f44Smeem 		pi->pi_hwaddrdup = _B_FALSE;
1520e11c3f44Smeem 	}
1521e11c3f44Smeem 
1522e11c3f44Smeem 	if (!change_pif_flags(pi, 0, IFF_OFFLINE))
1523e11c3f44Smeem 		return (IPMP_FAILURE);
1524e11c3f44Smeem 
1525e11c3f44Smeem 	/*
1526e11c3f44Smeem 	 * While the interface was offline, it may have failed (e.g. the link
1527e11c3f44Smeem 	 * may have gone down).  phyint_inst_check_for_failure() will have
1528e11c3f44Smeem 	 * already set pi_flags with IFF_FAILED, so we can use that to decide
1529e11c3f44Smeem 	 * whether the phyint should transition to running.  Note that after
1530e11c3f44Smeem 	 * we transition to running, we will start sending probes again (if
1531e11c3f44Smeem 	 * test addresses are configured), which may also reveal that the
1532e11c3f44Smeem 	 * interface is in fact failed.
1533e11c3f44Smeem 	 */
1534e11c3f44Smeem 	if (pi->pi_flags & IFF_FAILED) {
1535e11c3f44Smeem 		phyint_chstate(pi, PI_FAILED);
1536e11c3f44Smeem 	} else {
1537e11c3f44Smeem 		/* calls phyint_chstate() */
1538e11c3f44Smeem 		phyint_transition_to_running(pi);
1539e11c3f44Smeem 	}
1540e11c3f44Smeem 
1541e11c3f44Smeem 	/*
1542e11c3f44Smeem 	 * Give the requestor time to configure test addresses before
1543e11c3f44Smeem 	 * complaining that they're missing.
1544e11c3f44Smeem 	 */
1545e11c3f44Smeem 	pi->pi_taddrthresh = getcurrentsec() + TESTADDR_CONF_TIME;
1546e11c3f44Smeem 
1547e11c3f44Smeem 	return (IPMP_SUCCESS);
15487c478bd9Sstevel@tonic-gate }
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate /*
15517c478bd9Sstevel@tonic-gate  * Delete (unlink and free), the phyint instance.
15527c478bd9Sstevel@tonic-gate  */
15537c478bd9Sstevel@tonic-gate void
phyint_inst_delete(struct phyint_instance * pii)15547c478bd9Sstevel@tonic-gate phyint_inst_delete(struct phyint_instance *pii)
15557c478bd9Sstevel@tonic-gate {
15567c478bd9Sstevel@tonic-gate 	struct phyint *pi = pii->pii_phyint;
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 	assert(pi != NULL);
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
15617c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_delete(%s %s)\n",
15627c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pi->pi_name);
15637c478bd9Sstevel@tonic-gate 	}
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	/*
15667c478bd9Sstevel@tonic-gate 	 * If the phyint instance has associated probe targets
15677c478bd9Sstevel@tonic-gate 	 * delete all the targets
15687c478bd9Sstevel@tonic-gate 	 */
15697c478bd9Sstevel@tonic-gate 	while (pii->pii_targets != NULL)
15707c478bd9Sstevel@tonic-gate 		target_delete(pii->pii_targets);
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	/*
15737c478bd9Sstevel@tonic-gate 	 * Delete all the logints associated with this phyint
15747c478bd9Sstevel@tonic-gate 	 * instance.
15757c478bd9Sstevel@tonic-gate 	 */
15767c478bd9Sstevel@tonic-gate 	while (pii->pii_logint != NULL)
15777c478bd9Sstevel@tonic-gate 		logint_delete(pii->pii_logint);
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	/*
1580921e7e07Smeem 	 * Close the socket used to send probes to targets from this phyint.
15817c478bd9Sstevel@tonic-gate 	 */
15827c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock != -1)
15837c478bd9Sstevel@tonic-gate 		close_probe_socket(pii, _B_TRUE);
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 	/*
15867c478bd9Sstevel@tonic-gate 	 * Phyint instance must be in the list of all phyint instances.
15877c478bd9Sstevel@tonic-gate 	 * Remove phyint instance from the global list of phyint instances.
15887c478bd9Sstevel@tonic-gate 	 */
15897c478bd9Sstevel@tonic-gate 	assert(phyint_instances == pii || pii->pii_prev != NULL);
15907c478bd9Sstevel@tonic-gate 	if (pii->pii_prev == NULL) {
15917c478bd9Sstevel@tonic-gate 		/* Phyint is the 1st in the list */
15927c478bd9Sstevel@tonic-gate 		phyint_instances = pii->pii_next;
15937c478bd9Sstevel@tonic-gate 	} else {
15947c478bd9Sstevel@tonic-gate 		pii->pii_prev->pii_next = pii->pii_next;
15957c478bd9Sstevel@tonic-gate 	}
15967c478bd9Sstevel@tonic-gate 	if (pii->pii_next != NULL)
15977c478bd9Sstevel@tonic-gate 		pii->pii_next->pii_prev = pii->pii_prev;
15987c478bd9Sstevel@tonic-gate 	pii->pii_next = NULL;
15997c478bd9Sstevel@tonic-gate 	pii->pii_prev = NULL;
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	/*
16027c478bd9Sstevel@tonic-gate 	 * Reset the phyint instance pointer in the phyint.
16037c478bd9Sstevel@tonic-gate 	 * If this is the last phyint instance (being deleted) on this
16047c478bd9Sstevel@tonic-gate 	 * phyint, then delete the phyint.
16057c478bd9Sstevel@tonic-gate 	 */
16067c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET)
16077c478bd9Sstevel@tonic-gate 		pi->pi_v4 = NULL;
16087c478bd9Sstevel@tonic-gate 	else
16097c478bd9Sstevel@tonic-gate 		pi->pi_v6 = NULL;
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 	if (pi->pi_v4 == NULL && pi->pi_v6 == NULL)
16127c478bd9Sstevel@tonic-gate 		phyint_delete(pi);
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	free(pii);
16157c478bd9Sstevel@tonic-gate }
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate static void
phyint_inst_print(struct phyint_instance * pii)16187c478bd9Sstevel@tonic-gate phyint_inst_print(struct phyint_instance *pii)
16197c478bd9Sstevel@tonic-gate {
16207c478bd9Sstevel@tonic-gate 	struct logint *li;
16217c478bd9Sstevel@tonic-gate 	struct target *tg;
16227c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
16237c478bd9Sstevel@tonic-gate 	int most_recent;
16247c478bd9Sstevel@tonic-gate 	int i;
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	if (pii->pii_phyint == NULL) {
16277c478bd9Sstevel@tonic-gate 		logdebug("pii->pi_phyint NULL can't print\n");
16287c478bd9Sstevel@tonic-gate 		return;
16297c478bd9Sstevel@tonic-gate 	}
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	logdebug("\nPhyint instance: %s %s index %u state %x flags %llx	 "
1632e11c3f44Smeem 	    "sock %x in_use %d\n",
16337c478bd9Sstevel@tonic-gate 	    AF_STR(pii->pii_af), pii->pii_name, pii->pii_ifindex,
16347c478bd9Sstevel@tonic-gate 	    pii->pii_state, pii->pii_phyint->pi_flags, pii->pii_probe_sock,
1635e11c3f44Smeem 	    pii->pii_in_use);
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	for (li = pii->pii_logint; li != NULL; li = li->li_next)
16387c478bd9Sstevel@tonic-gate 		logint_print(li);
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	logdebug("\n");
16417c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next)
16427c478bd9Sstevel@tonic-gate 		target_print(tg);
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	if (pii->pii_targets == NULL)
16457c478bd9Sstevel@tonic-gate 		logdebug("pi_targets NULL\n");
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	if (pii->pii_target_next != NULL) {
16487c478bd9Sstevel@tonic-gate 		logdebug("pi_target_next %s %s\n", AF_STR(pii->pii_af),
16497c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, pii->pii_target_next->tg_address,
16507c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)));
16517c478bd9Sstevel@tonic-gate 	} else {
16527c478bd9Sstevel@tonic-gate 		logdebug("pi_target_next NULL\n");
16537c478bd9Sstevel@tonic-gate 	}
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	if (pii->pii_rtt_target_next != NULL) {
16567c478bd9Sstevel@tonic-gate 		logdebug("pi_rtt_target_next %s %s\n", AF_STR(pii->pii_af),
16577c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, pii->pii_rtt_target_next->tg_address,
16587c478bd9Sstevel@tonic-gate 		    abuf, sizeof (abuf)));
16597c478bd9Sstevel@tonic-gate 	} else {
16607c478bd9Sstevel@tonic-gate 		logdebug("pi_rtt_target_next NULL\n");
16617c478bd9Sstevel@tonic-gate 	}
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	if (pii->pii_targets != NULL) {
16647c478bd9Sstevel@tonic-gate 		most_recent = PROBE_INDEX_PREV(pii->pii_probe_next);
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate 		i = most_recent;
16677c478bd9Sstevel@tonic-gate 		do {
16687c478bd9Sstevel@tonic-gate 			if (pii->pii_probes[i].pr_target != NULL) {
16697c478bd9Sstevel@tonic-gate 				logdebug("#%d target %s ", i,
16707c478bd9Sstevel@tonic-gate 				    pr_addr(pii->pii_af,
16717c478bd9Sstevel@tonic-gate 				    pii->pii_probes[i].pr_target->tg_address,
16727c478bd9Sstevel@tonic-gate 				    abuf, sizeof (abuf)));
16737c478bd9Sstevel@tonic-gate 			} else {
16747c478bd9Sstevel@tonic-gate 				logdebug("#%d target NULL ", i);
16757c478bd9Sstevel@tonic-gate 			}
1676e11c3f44Smeem 			logdebug("time_start %lld status %d "
1677e11c3f44Smeem 			    "time_ackproc %lld time_lost %u",
1678e11c3f44Smeem 			    pii->pii_probes[i].pr_hrtime_start,
16797c478bd9Sstevel@tonic-gate 			    pii->pii_probes[i].pr_status,
1680e11c3f44Smeem 			    pii->pii_probes[i].pr_hrtime_ackproc,
16817c478bd9Sstevel@tonic-gate 			    pii->pii_probes[i].pr_time_lost);
16827c478bd9Sstevel@tonic-gate 			i = PROBE_INDEX_PREV(i);
16837c478bd9Sstevel@tonic-gate 		} while (i != most_recent);
16847c478bd9Sstevel@tonic-gate 	}
16857c478bd9Sstevel@tonic-gate }
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate /*
16887c478bd9Sstevel@tonic-gate  * Lookup a logint based on the logical interface name, on the given
16897c478bd9Sstevel@tonic-gate  * phyint instance.
16907c478bd9Sstevel@tonic-gate  */
16917c478bd9Sstevel@tonic-gate static struct logint *
logint_lookup(struct phyint_instance * pii,char * name)16927c478bd9Sstevel@tonic-gate logint_lookup(struct phyint_instance *pii, char *name)
16937c478bd9Sstevel@tonic-gate {
16947c478bd9Sstevel@tonic-gate 	struct logint *li;
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
16977c478bd9Sstevel@tonic-gate 		logdebug("logint_lookup(%s, %s)\n",
16987c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), name);
16997c478bd9Sstevel@tonic-gate 	}
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	for (li = pii->pii_logint; li != NULL; li = li->li_next) {
17027c478bd9Sstevel@tonic-gate 		if (strncmp(name, li->li_name, sizeof (li->li_name)) == 0)
17037c478bd9Sstevel@tonic-gate 			break;
17047c478bd9Sstevel@tonic-gate 	}
17057c478bd9Sstevel@tonic-gate 	return (li);
17067c478bd9Sstevel@tonic-gate }
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate /*
17097c478bd9Sstevel@tonic-gate  * Insert a logint at the head of the list of logints of the given
17107c478bd9Sstevel@tonic-gate  * phyint instance
17117c478bd9Sstevel@tonic-gate  */
17127c478bd9Sstevel@tonic-gate static void
logint_insert(struct phyint_instance * pii,struct logint * li)17137c478bd9Sstevel@tonic-gate logint_insert(struct phyint_instance *pii, struct logint *li)
17147c478bd9Sstevel@tonic-gate {
17157c478bd9Sstevel@tonic-gate 	li->li_next = pii->pii_logint;
17167c478bd9Sstevel@tonic-gate 	li->li_prev = NULL;
17177c478bd9Sstevel@tonic-gate 	if (pii->pii_logint != NULL)
17187c478bd9Sstevel@tonic-gate 		pii->pii_logint->li_prev = li;
17197c478bd9Sstevel@tonic-gate 	pii->pii_logint = li;
17207c478bd9Sstevel@tonic-gate 	li->li_phyint_inst = pii;
17217c478bd9Sstevel@tonic-gate }
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate /*
17247c478bd9Sstevel@tonic-gate  * Create a new named logint, on the specified phyint instance.
17257c478bd9Sstevel@tonic-gate  */
17267c478bd9Sstevel@tonic-gate static struct logint *
logint_create(struct phyint_instance * pii,char * name)17277c478bd9Sstevel@tonic-gate logint_create(struct phyint_instance *pii, char *name)
17287c478bd9Sstevel@tonic-gate {
17297c478bd9Sstevel@tonic-gate 	struct logint *li;
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
17327c478bd9Sstevel@tonic-gate 		logdebug("logint_create(%s %s %s)\n",
17337c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name, name);
17347c478bd9Sstevel@tonic-gate 	}
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 	li = calloc(1, sizeof (struct logint));
17377c478bd9Sstevel@tonic-gate 	if (li == NULL) {
17387c478bd9Sstevel@tonic-gate 		logperror("logint_create: calloc");
17397c478bd9Sstevel@tonic-gate 		return (NULL);
17407c478bd9Sstevel@tonic-gate 	}
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 	(void) strncpy(li->li_name, name, sizeof (li->li_name));
17437c478bd9Sstevel@tonic-gate 	li->li_name[sizeof (li->li_name) - 1] = '\0';
17447c478bd9Sstevel@tonic-gate 	logint_insert(pii, li);
17457c478bd9Sstevel@tonic-gate 	return (li);
17467c478bd9Sstevel@tonic-gate }
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate /*
17497c478bd9Sstevel@tonic-gate  * Initialize the logint based on the data returned by the kernel.
17507c478bd9Sstevel@tonic-gate  */
17517c478bd9Sstevel@tonic-gate void
logint_init_from_k(struct phyint_instance * pii,char * li_name)17527c478bd9Sstevel@tonic-gate logint_init_from_k(struct phyint_instance *pii, char *li_name)
17537c478bd9Sstevel@tonic-gate {
17547c478bd9Sstevel@tonic-gate 	int	ifsock;
17557c478bd9Sstevel@tonic-gate 	uint64_t flags;
17567c478bd9Sstevel@tonic-gate 	uint64_t saved_flags;
17577c478bd9Sstevel@tonic-gate 	struct	logint	*li;
17587c478bd9Sstevel@tonic-gate 	struct lifreq	lifr;
17597c478bd9Sstevel@tonic-gate 	struct in6_addr	test_subnet;
17607c478bd9Sstevel@tonic-gate 	struct in6_addr	testaddr;
17617c478bd9Sstevel@tonic-gate 	int	test_subnet_len;
17627c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
17637c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin;
17647c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
17657c478bd9Sstevel@tonic-gate 	boolean_t  ptp = _B_FALSE;
17667c478bd9Sstevel@tonic-gate 	struct in6_addr tgaddr;
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
17697c478bd9Sstevel@tonic-gate 		logdebug("logint_init_from_k(%s %s)\n",
17707c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), li_name);
17717c478bd9Sstevel@tonic-gate 	}
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	/* Get the socket for doing ioctls */
17747c478bd9Sstevel@tonic-gate 	ifsock = (pii->pii_af == AF_INET) ? ifsock_v4 : ifsock_v6;
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	/*
17777c478bd9Sstevel@tonic-gate 	 * Get the flags from the kernel. Also serves as a check whether
17787c478bd9Sstevel@tonic-gate 	 * the logical still exists. If it doesn't exist, no need to proceed
17797c478bd9Sstevel@tonic-gate 	 * any further. li_in_use will make the caller clean up the logint
17807c478bd9Sstevel@tonic-gate 	 */
17817c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, li_name, sizeof (lifr.lifr_name));
17827c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
17837c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
17847c478bd9Sstevel@tonic-gate 		/* Interface may have vanished */
17857c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
17867c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "logint_init_from_k: "
17877c478bd9Sstevel@tonic-gate 			    "ioctl (get flags)");
17887c478bd9Sstevel@tonic-gate 		}
17897c478bd9Sstevel@tonic-gate 		return;
17907c478bd9Sstevel@tonic-gate 	}
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 	flags = lifr.lifr_flags;
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 	/*
17957c478bd9Sstevel@tonic-gate 	 * Verified the logint exists. Now lookup the logint in our tables.
17967c478bd9Sstevel@tonic-gate 	 * If it does not exist, create a new logint.
17977c478bd9Sstevel@tonic-gate 	 */
17987c478bd9Sstevel@tonic-gate 	li = logint_lookup(pii, li_name);
17997c478bd9Sstevel@tonic-gate 	if (li == NULL) {
18007c478bd9Sstevel@tonic-gate 		li = logint_create(pii, li_name);
18017c478bd9Sstevel@tonic-gate 		if (li == NULL) {
18027c478bd9Sstevel@tonic-gate 			/*
18037c478bd9Sstevel@tonic-gate 			 * Pretend the interface does not exist
18047c478bd9Sstevel@tonic-gate 			 * in the kernel
18057c478bd9Sstevel@tonic-gate 			 */
18067c478bd9Sstevel@tonic-gate 			return;
18077c478bd9Sstevel@tonic-gate 		}
18087c478bd9Sstevel@tonic-gate 	}
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	/*
18117c478bd9Sstevel@tonic-gate 	 * Update li->li_flags with the new flags, after saving the old
18127c478bd9Sstevel@tonic-gate 	 * value. This is used later to check what flags has changed and
18137c478bd9Sstevel@tonic-gate 	 * take any action
18147c478bd9Sstevel@tonic-gate 	 */
18157c478bd9Sstevel@tonic-gate 	saved_flags = li->li_flags;
18167c478bd9Sstevel@tonic-gate 	li->li_flags = flags;
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 	/*
18197c478bd9Sstevel@tonic-gate 	 * Get the address, prefix, prefixlength and update the logint.
18207c478bd9Sstevel@tonic-gate 	 * Check if anything has changed. If the logint used for the
18217c478bd9Sstevel@tonic-gate 	 * test address has changed, take suitable action.
18227c478bd9Sstevel@tonic-gate 	 */
18237c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFADDR, (char *)&lifr) < 0) {
18247c478bd9Sstevel@tonic-gate 		/* Interface may have vanished */
18257c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
18267c478bd9Sstevel@tonic-gate 			logperror_li(li, "logint_init_from_k: (get addr)");
18277c478bd9Sstevel@tonic-gate 		}
18287c478bd9Sstevel@tonic-gate 		goto error;
18297c478bd9Sstevel@tonic-gate 	}
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET) {
18327c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
18337c478bd9Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &testaddr);
18347c478bd9Sstevel@tonic-gate 	} else {
18357c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
18367c478bd9Sstevel@tonic-gate 		testaddr = sin6->sin6_addr;
18377c478bd9Sstevel@tonic-gate 	}
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFSUBNET, (char *)&lifr) < 0) {
18407c478bd9Sstevel@tonic-gate 		/* Interface may have vanished */
1841e11c3f44Smeem 		if (errno != ENXIO)
1842e11c3f44Smeem 			logperror_li(li, "logint_init_from_k: (get subnet)");
18437c478bd9Sstevel@tonic-gate 		goto error;
18447c478bd9Sstevel@tonic-gate 	}
18457c478bd9Sstevel@tonic-gate 	if (lifr.lifr_subnet.ss_family == AF_INET6) {
18467c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_subnet;
18477c478bd9Sstevel@tonic-gate 		test_subnet = sin6->sin6_addr;
18487c478bd9Sstevel@tonic-gate 		test_subnet_len = lifr.lifr_addrlen;
18497c478bd9Sstevel@tonic-gate 	} else {
18507c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)&lifr.lifr_subnet;
18517c478bd9Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &test_subnet);
1852e11c3f44Smeem 		test_subnet_len = lifr.lifr_addrlen + (IPV6_ABITS - IP_ABITS);
18537c478bd9Sstevel@tonic-gate 	}
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	/*
18567c478bd9Sstevel@tonic-gate 	 * If this is the logint corresponding to the test address used for
18577c478bd9Sstevel@tonic-gate 	 * sending probes, then if anything significant has changed we need to
18587c478bd9Sstevel@tonic-gate 	 * determine the test address again.  We ignore changes to the
18597c478bd9Sstevel@tonic-gate 	 * IFF_FAILED and IFF_RUNNING flags since those happen as a matter of
18607c478bd9Sstevel@tonic-gate 	 * course.
18617c478bd9Sstevel@tonic-gate 	 */
18627c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_logint == li) {
18637c478bd9Sstevel@tonic-gate 		if (((li->li_flags ^ saved_flags) &
18647c478bd9Sstevel@tonic-gate 		    ~(IFF_FAILED | IFF_RUNNING)) != 0 ||
18657c478bd9Sstevel@tonic-gate 		    !IN6_ARE_ADDR_EQUAL(&testaddr, &li->li_addr) ||
18667c478bd9Sstevel@tonic-gate 		    (!ptp && !IN6_ARE_ADDR_EQUAL(&test_subnet,
18677c478bd9Sstevel@tonic-gate 		    &li->li_subnet)) ||
18687c478bd9Sstevel@tonic-gate 		    (!ptp && test_subnet_len != li->li_subnet_len) ||
18697c478bd9Sstevel@tonic-gate 		    (ptp && !IN6_ARE_ADDR_EQUAL(&tgaddr, &li->li_dstaddr))) {
18707c478bd9Sstevel@tonic-gate 			/*
18717c478bd9Sstevel@tonic-gate 			 * Something significant that affects the testaddress
18727c478bd9Sstevel@tonic-gate 			 * has changed. Redo the testaddress selection later on
18737c478bd9Sstevel@tonic-gate 			 * in select_test_ifs(). For now do the cleanup and
18747c478bd9Sstevel@tonic-gate 			 * set pii_probe_logint to NULL.
18757c478bd9Sstevel@tonic-gate 			 */
18767c478bd9Sstevel@tonic-gate 			if (pii->pii_probe_sock != -1)
18777c478bd9Sstevel@tonic-gate 				close_probe_socket(pii, _B_TRUE);
18787c478bd9Sstevel@tonic-gate 			pii->pii_probe_logint = NULL;
18797c478bd9Sstevel@tonic-gate 		}
18807c478bd9Sstevel@tonic-gate 	}
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	/* Update the logint with the values obtained from the kernel.	*/
18847c478bd9Sstevel@tonic-gate 	li->li_addr = testaddr;
18857c478bd9Sstevel@tonic-gate 	li->li_in_use = 1;
18867c478bd9Sstevel@tonic-gate 	if (ptp) {
18877c478bd9Sstevel@tonic-gate 		li->li_dstaddr = tgaddr;
18887c478bd9Sstevel@tonic-gate 		li->li_subnet_len = (pii->pii_af == AF_INET) ?
18897c478bd9Sstevel@tonic-gate 		    IP_ABITS : IPV6_ABITS;
18907c478bd9Sstevel@tonic-gate 	} else {
18917c478bd9Sstevel@tonic-gate 		li->li_subnet = test_subnet;
18927c478bd9Sstevel@tonic-gate 		li->li_subnet_len = test_subnet_len;
18937c478bd9Sstevel@tonic-gate 	}
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT)
18967c478bd9Sstevel@tonic-gate 		logint_print(li);
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	return;
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate error:
19017c478bd9Sstevel@tonic-gate 	logerr("logint_init_from_k: IGNORED %s %s %s addr %s\n",
19027c478bd9Sstevel@tonic-gate 	    AF_STR(pii->pii_af), pii->pii_name, li->li_name,
19037c478bd9Sstevel@tonic-gate 	    pr_addr(pii->pii_af, testaddr, abuf, sizeof (abuf)));
19047c478bd9Sstevel@tonic-gate 	logint_delete(li);
19057c478bd9Sstevel@tonic-gate }
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate /*
19087c478bd9Sstevel@tonic-gate  * Delete (unlink and free) a logint.
19097c478bd9Sstevel@tonic-gate  */
19107c478bd9Sstevel@tonic-gate void
logint_delete(struct logint * li)19117c478bd9Sstevel@tonic-gate logint_delete(struct logint *li)
19127c478bd9Sstevel@tonic-gate {
19137c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	pii = li->li_phyint_inst;
19167c478bd9Sstevel@tonic-gate 	assert(pii != NULL);
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
19197c478bd9Sstevel@tonic-gate 		int af;
19207c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 		af = pii->pii_af;
19237c478bd9Sstevel@tonic-gate 		logdebug("logint_delete(%s %s %s/%u)\n",
19247c478bd9Sstevel@tonic-gate 		    AF_STR(af), li->li_name,
19257c478bd9Sstevel@tonic-gate 		    pr_addr(af, li->li_addr, abuf, sizeof (abuf)),
19267c478bd9Sstevel@tonic-gate 		    li->li_subnet_len);
19277c478bd9Sstevel@tonic-gate 	}
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 	/* logint must be in the list of logints */
19307c478bd9Sstevel@tonic-gate 	assert(pii->pii_logint == li || li->li_prev != NULL);
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate 	/* Remove the logint from the list of logints  */
19337c478bd9Sstevel@tonic-gate 	if (li->li_prev == NULL) {
19347c478bd9Sstevel@tonic-gate 		/* logint is the 1st in the list */
19357c478bd9Sstevel@tonic-gate 		pii->pii_logint = li->li_next;
19367c478bd9Sstevel@tonic-gate 	} else {
19377c478bd9Sstevel@tonic-gate 		li->li_prev->li_next = li->li_next;
19387c478bd9Sstevel@tonic-gate 	}
19397c478bd9Sstevel@tonic-gate 	if (li->li_next != NULL)
19407c478bd9Sstevel@tonic-gate 		li->li_next->li_prev = li->li_prev;
19417c478bd9Sstevel@tonic-gate 	li->li_next = NULL;
19427c478bd9Sstevel@tonic-gate 	li->li_prev = NULL;
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	/*
1945921e7e07Smeem 	 * If this logint is also being used for probing, then close the
1946921e7e07Smeem 	 * associated socket, if it exists.
19477c478bd9Sstevel@tonic-gate 	 */
19487c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_logint == li) {
19497c478bd9Sstevel@tonic-gate 		if (pii->pii_probe_sock != -1)
19507c478bd9Sstevel@tonic-gate 			close_probe_socket(pii, _B_TRUE);
19517c478bd9Sstevel@tonic-gate 		pii->pii_probe_logint = NULL;
19527c478bd9Sstevel@tonic-gate 	}
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 	free(li);
19557c478bd9Sstevel@tonic-gate }
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate static void
logint_print(struct logint * li)19587c478bd9Sstevel@tonic-gate logint_print(struct logint *li)
19597c478bd9Sstevel@tonic-gate {
19607c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1961e11c3f44Smeem 	int af = li->li_phyint_inst->pii_af;
19627c478bd9Sstevel@tonic-gate 
19637c478bd9Sstevel@tonic-gate 	logdebug("logint: %s %s addr %s/%u", AF_STR(af), li->li_name,
19647c478bd9Sstevel@tonic-gate 	    pr_addr(af, li->li_addr, abuf, sizeof (abuf)), li->li_subnet_len);
19657c478bd9Sstevel@tonic-gate 
1966e11c3f44Smeem 	logdebug("\tFlags: %llx in_use %d\n", li->li_flags, li->li_in_use);
19677c478bd9Sstevel@tonic-gate }
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate char *
pr_addr(int af,struct in6_addr addr,char * abuf,int len)19707c478bd9Sstevel@tonic-gate pr_addr(int af, struct in6_addr addr, char *abuf, int len)
19717c478bd9Sstevel@tonic-gate {
19727c478bd9Sstevel@tonic-gate 	struct in_addr	addr_v4;
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
19757c478bd9Sstevel@tonic-gate 		IN6_V4MAPPED_TO_INADDR(&addr, &addr_v4);
19767c478bd9Sstevel@tonic-gate 		(void) inet_ntop(AF_INET, (void *)&addr_v4, abuf, len);
19777c478bd9Sstevel@tonic-gate 	} else {
19787c478bd9Sstevel@tonic-gate 		(void) inet_ntop(AF_INET6, (void *)&addr, abuf, len);
19797c478bd9Sstevel@tonic-gate 	}
19807c478bd9Sstevel@tonic-gate 	return (abuf);
19817c478bd9Sstevel@tonic-gate }
19827c478bd9Sstevel@tonic-gate 
1983e11c3f44Smeem /*
1984e11c3f44Smeem  * Fill in the sockaddr_storage pointed to by `ssp' with the IP address
1985e11c3f44Smeem  * represented by the [`af',`addr'] pair.  Needed because in.mpathd internally
1986e11c3f44Smeem  * stores all addresses as in6_addrs, but we don't want to expose that.
1987e11c3f44Smeem  */
1988e11c3f44Smeem void
addr2storage(int af,const struct in6_addr * addr,struct sockaddr_storage * ssp)1989e11c3f44Smeem addr2storage(int af, const struct in6_addr *addr, struct sockaddr_storage *ssp)
1990e11c3f44Smeem {
1991e11c3f44Smeem 	struct sockaddr_in *sinp = (struct sockaddr_in *)ssp;
1992e11c3f44Smeem 	struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *)ssp;
1993e11c3f44Smeem 
1994e11c3f44Smeem 	assert(af == AF_INET || af == AF_INET6);
1995e11c3f44Smeem 
1996e11c3f44Smeem 	switch (af) {
1997e11c3f44Smeem 	case AF_INET:
1998e11c3f44Smeem 		(void) memset(sinp, 0, sizeof (*sinp));
1999e11c3f44Smeem 		sinp->sin_family = AF_INET;
2000e11c3f44Smeem 		IN6_V4MAPPED_TO_INADDR(addr, &sinp->sin_addr);
2001e11c3f44Smeem 		break;
2002e11c3f44Smeem 	case AF_INET6:
2003e11c3f44Smeem 		(void) memset(sin6p, 0, sizeof (*sin6p));
2004e11c3f44Smeem 		sin6p->sin6_family = AF_INET6;
2005e11c3f44Smeem 		sin6p->sin6_addr = *addr;
2006e11c3f44Smeem 		break;
2007e11c3f44Smeem 	}
2008e11c3f44Smeem }
2009e11c3f44Smeem 
20107c478bd9Sstevel@tonic-gate /* Lookup target on its address */
20117c478bd9Sstevel@tonic-gate struct target *
target_lookup(struct phyint_instance * pii,struct in6_addr addr)20127c478bd9Sstevel@tonic-gate target_lookup(struct phyint_instance *pii, struct in6_addr addr)
20137c478bd9Sstevel@tonic-gate {
20147c478bd9Sstevel@tonic-gate 	struct target *tg;
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET) {
20177c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 		logdebug("target_lookup(%s %s): addr %s\n",
20207c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name,
20217c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, addr, abuf, sizeof (abuf)));
20227c478bd9Sstevel@tonic-gate 	}
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) {
20257c478bd9Sstevel@tonic-gate 		if (IN6_ARE_ADDR_EQUAL(&tg->tg_address, &addr))
20267c478bd9Sstevel@tonic-gate 			break;
20277c478bd9Sstevel@tonic-gate 	}
20287c478bd9Sstevel@tonic-gate 	return (tg);
20297c478bd9Sstevel@tonic-gate }
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate /*
20327c478bd9Sstevel@tonic-gate  * Find and return the next active target, for the next probe.
20337c478bd9Sstevel@tonic-gate  * If no active targets are available, return NULL.
20347c478bd9Sstevel@tonic-gate  */
20357c478bd9Sstevel@tonic-gate struct target *
target_next(struct target * tg)20367c478bd9Sstevel@tonic-gate target_next(struct target *tg)
20377c478bd9Sstevel@tonic-gate {
20387c478bd9Sstevel@tonic-gate 	struct	phyint_instance	*pii = tg->tg_phyint_inst;
20397c478bd9Sstevel@tonic-gate 	struct	target	*marker = tg;
20407c478bd9Sstevel@tonic-gate 	hrtime_t now;
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate 	now = gethrtime();
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 	/*
20457c478bd9Sstevel@tonic-gate 	 * Target must be in the list of targets for this phyint
20467c478bd9Sstevel@tonic-gate 	 * instance.
20477c478bd9Sstevel@tonic-gate 	 */
20487c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets == tg || tg->tg_prev != NULL);
20497c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets != NULL);
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	/* Return the next active target */
20527c478bd9Sstevel@tonic-gate 	do {
20537c478bd9Sstevel@tonic-gate 		/*
20547c478bd9Sstevel@tonic-gate 		 * Go to the next target. If we hit the end,
20557c478bd9Sstevel@tonic-gate 		 * reset the ptr to the head
20567c478bd9Sstevel@tonic-gate 		 */
20577c478bd9Sstevel@tonic-gate 		tg = tg->tg_next;
20587c478bd9Sstevel@tonic-gate 		if (tg == NULL)
20597c478bd9Sstevel@tonic-gate 			tg = pii->pii_targets;
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 		switch (tg->tg_status) {
20647c478bd9Sstevel@tonic-gate 		case TG_ACTIVE:
20657c478bd9Sstevel@tonic-gate 			return (tg);
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 		case TG_UNUSED:
20687c478bd9Sstevel@tonic-gate 			assert(pii->pii_targets_are_routers);
20697c478bd9Sstevel@tonic-gate 			if (pii->pii_ntargets < MAX_PROBE_TARGETS) {
20707c478bd9Sstevel@tonic-gate 				/*
20717c478bd9Sstevel@tonic-gate 				 * Bubble up the unused target to active
20727c478bd9Sstevel@tonic-gate 				 */
20737c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_ACTIVE;
20747c478bd9Sstevel@tonic-gate 				pii->pii_ntargets++;
20757c478bd9Sstevel@tonic-gate 				return (tg);
20767c478bd9Sstevel@tonic-gate 			}
20777c478bd9Sstevel@tonic-gate 			break;
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate 		case TG_SLOW:
20807c478bd9Sstevel@tonic-gate 			assert(pii->pii_targets_are_routers);
20817c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
20827c478bd9Sstevel@tonic-gate 				/*
20837c478bd9Sstevel@tonic-gate 				 * Bubble up the slow target to unused
20847c478bd9Sstevel@tonic-gate 				 */
20857c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_UNUSED;
20867c478bd9Sstevel@tonic-gate 			}
20877c478bd9Sstevel@tonic-gate 			break;
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 		case TG_DEAD:
20907c478bd9Sstevel@tonic-gate 			assert(pii->pii_targets_are_routers);
20917c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
20927c478bd9Sstevel@tonic-gate 				/*
20937c478bd9Sstevel@tonic-gate 				 * Bubble up the dead target to slow
20947c478bd9Sstevel@tonic-gate 				 */
20957c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_SLOW;
20967c478bd9Sstevel@tonic-gate 				tg->tg_latime = now;
20977c478bd9Sstevel@tonic-gate 			}
20987c478bd9Sstevel@tonic-gate 			break;
20997c478bd9Sstevel@tonic-gate 		}
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	} while (tg != marker);
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 	return (NULL);
21047c478bd9Sstevel@tonic-gate }
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate /*
21077c478bd9Sstevel@tonic-gate  * Select the best available target, that is not already TG_ACTIVE,
21087c478bd9Sstevel@tonic-gate  * for the caller. The caller will determine whether it wants to
21097c478bd9Sstevel@tonic-gate  * make the returned target TG_ACTIVE.
21107c478bd9Sstevel@tonic-gate  * The selection order is as follows.
21117c478bd9Sstevel@tonic-gate  * 1. pick a TG_UNSED target, if it exists.
21127c478bd9Sstevel@tonic-gate  * 2. else pick a TG_SLOW target that has recovered, if it exists
21137c478bd9Sstevel@tonic-gate  * 3. else pick any TG_SLOW target, if it exists
21147c478bd9Sstevel@tonic-gate  * 4. else pick a TG_DEAD target that has recovered, if it exists
21157c478bd9Sstevel@tonic-gate  * 5. else pick any TG_DEAD target, if it exists
21167c478bd9Sstevel@tonic-gate  * 6. else return null
21177c478bd9Sstevel@tonic-gate  */
21187c478bd9Sstevel@tonic-gate static struct target *
target_select_best(struct phyint_instance * pii)21197c478bd9Sstevel@tonic-gate target_select_best(struct phyint_instance *pii)
21207c478bd9Sstevel@tonic-gate {
21217c478bd9Sstevel@tonic-gate 	struct target *tg;
21227c478bd9Sstevel@tonic-gate 	struct target *slow = NULL;
21237c478bd9Sstevel@tonic-gate 	struct target *dead = NULL;
21247c478bd9Sstevel@tonic-gate 	struct target *slow_recovered = NULL;
21257c478bd9Sstevel@tonic-gate 	struct target *dead_recovered = NULL;
21267c478bd9Sstevel@tonic-gate 	hrtime_t now;
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	now = gethrtime();
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) {
21317c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 		switch (tg->tg_status) {
21347c478bd9Sstevel@tonic-gate 		case TG_UNUSED:
21357c478bd9Sstevel@tonic-gate 			return (tg);
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 		case TG_SLOW:
21387c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
21397c478bd9Sstevel@tonic-gate 				slow_recovered = tg;
21407c478bd9Sstevel@tonic-gate 				/*
2141e11c3f44Smeem 				 * Promote the slow_recovered to unused
21427c478bd9Sstevel@tonic-gate 				 */
21437c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_UNUSED;
21447c478bd9Sstevel@tonic-gate 			} else {
21457c478bd9Sstevel@tonic-gate 				slow = tg;
21467c478bd9Sstevel@tonic-gate 			}
21477c478bd9Sstevel@tonic-gate 			break;
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 		case TG_DEAD:
21507c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
21517c478bd9Sstevel@tonic-gate 				dead_recovered = tg;
21527c478bd9Sstevel@tonic-gate 				/*
2153e11c3f44Smeem 				 * Promote the dead_recovered to slow
21547c478bd9Sstevel@tonic-gate 				 */
21557c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_SLOW;
21567c478bd9Sstevel@tonic-gate 				tg->tg_latime = now;
21577c478bd9Sstevel@tonic-gate 			} else {
21587c478bd9Sstevel@tonic-gate 				dead = tg;
21597c478bd9Sstevel@tonic-gate 			}
21607c478bd9Sstevel@tonic-gate 			break;
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 		default:
21637c478bd9Sstevel@tonic-gate 			break;
21647c478bd9Sstevel@tonic-gate 		}
21657c478bd9Sstevel@tonic-gate 	}
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 	if (slow_recovered != NULL)
21687c478bd9Sstevel@tonic-gate 		return (slow_recovered);
21697c478bd9Sstevel@tonic-gate 	else if (slow != NULL)
21707c478bd9Sstevel@tonic-gate 		return (slow);
21717c478bd9Sstevel@tonic-gate 	else if (dead_recovered != NULL)
21727c478bd9Sstevel@tonic-gate 		return (dead_recovered);
21737c478bd9Sstevel@tonic-gate 	else
21747c478bd9Sstevel@tonic-gate 		return (dead);
21757c478bd9Sstevel@tonic-gate }
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate /*
21787c478bd9Sstevel@tonic-gate  * Some target was deleted. If we don't have even MIN_PROBE_TARGETS
21797c478bd9Sstevel@tonic-gate  * that are active, pick the next best below.
21807c478bd9Sstevel@tonic-gate  */
21817c478bd9Sstevel@tonic-gate static void
target_activate_all(struct phyint_instance * pii)21827c478bd9Sstevel@tonic-gate target_activate_all(struct phyint_instance *pii)
21837c478bd9Sstevel@tonic-gate {
21847c478bd9Sstevel@tonic-gate 	struct target *tg;
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	assert(pii->pii_ntargets == 0);
21877c478bd9Sstevel@tonic-gate 	assert(pii->pii_target_next == NULL);
21887c478bd9Sstevel@tonic-gate 	assert(pii->pii_rtt_target_next == NULL);
21897c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets_are_routers);
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 	while (pii->pii_ntargets < MIN_PROBE_TARGETS) {
21927c478bd9Sstevel@tonic-gate 		tg = target_select_best(pii);
21937c478bd9Sstevel@tonic-gate 		if (tg == NULL) {
21947c478bd9Sstevel@tonic-gate 			/* We are out of targets */
21957c478bd9Sstevel@tonic-gate 			return;
21967c478bd9Sstevel@tonic-gate 		}
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
21997c478bd9Sstevel@tonic-gate 		assert(tg->tg_status != TG_ACTIVE);
22007c478bd9Sstevel@tonic-gate 		tg->tg_status = TG_ACTIVE;
22017c478bd9Sstevel@tonic-gate 		pii->pii_ntargets++;
22027c478bd9Sstevel@tonic-gate 		if (pii->pii_target_next == NULL) {
22037c478bd9Sstevel@tonic-gate 			pii->pii_target_next = tg;
22047c478bd9Sstevel@tonic-gate 			pii->pii_rtt_target_next = tg;
22057c478bd9Sstevel@tonic-gate 		}
22067c478bd9Sstevel@tonic-gate 	}
22077c478bd9Sstevel@tonic-gate }
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate static struct target *
target_first(struct phyint_instance * pii)22107c478bd9Sstevel@tonic-gate target_first(struct phyint_instance *pii)
22117c478bd9Sstevel@tonic-gate {
22127c478bd9Sstevel@tonic-gate 	struct target *tg;
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) {
22157c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
22167c478bd9Sstevel@tonic-gate 		if (tg->tg_status == TG_ACTIVE)
22177c478bd9Sstevel@tonic-gate 			break;
22187c478bd9Sstevel@tonic-gate 	}
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	return (tg);
22217c478bd9Sstevel@tonic-gate }
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate /*
22247c478bd9Sstevel@tonic-gate  * Create a default target entry.
22257c478bd9Sstevel@tonic-gate  */
22267c478bd9Sstevel@tonic-gate void
target_create(struct phyint_instance * pii,struct in6_addr addr,boolean_t is_router)22277c478bd9Sstevel@tonic-gate target_create(struct phyint_instance *pii, struct in6_addr addr,
22287c478bd9Sstevel@tonic-gate     boolean_t is_router)
22297c478bd9Sstevel@tonic-gate {
22307c478bd9Sstevel@tonic-gate 	struct target *tg;
22317c478bd9Sstevel@tonic-gate 	struct phyint *pi;
22327c478bd9Sstevel@tonic-gate 	struct logint *li;
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET) {
22357c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 		logdebug("target_create(%s %s, %s)\n",
22387c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name,
22397c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, addr, abuf, sizeof (abuf)));
22407c478bd9Sstevel@tonic-gate 	}
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate 	/*
22437c478bd9Sstevel@tonic-gate 	 * If the test address is not yet initialized, do not add
22447c478bd9Sstevel@tonic-gate 	 * any target, since we cannot determine whether the target
22457c478bd9Sstevel@tonic-gate 	 * belongs to the same subnet as the test address.
22467c478bd9Sstevel@tonic-gate 	 */
22477c478bd9Sstevel@tonic-gate 	li = pii->pii_probe_logint;
22487c478bd9Sstevel@tonic-gate 	if (li == NULL)
22497c478bd9Sstevel@tonic-gate 		return;
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 	/*
22527c478bd9Sstevel@tonic-gate 	 * If there are multiple subnets associated with an interface, then
2253e11c3f44Smeem 	 * add the target to this phyint instance only if it belongs to the
2254e11c3f44Smeem 	 * same subnet as the test address.  This assures us that we will
2255e11c3f44Smeem 	 * be able to reach this target through our routing table.
22567c478bd9Sstevel@tonic-gate 	 */
22577c478bd9Sstevel@tonic-gate 	if (!prefix_equal(li->li_subnet, addr, li->li_subnet_len))
22587c478bd9Sstevel@tonic-gate 		return;
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate 	if (pii->pii_targets != NULL) {
22617c478bd9Sstevel@tonic-gate 		assert(pii->pii_ntargets <= MAX_PROBE_TARGETS);
22627c478bd9Sstevel@tonic-gate 		if (is_router) {
22637c478bd9Sstevel@tonic-gate 			if (!pii->pii_targets_are_routers) {
22647c478bd9Sstevel@tonic-gate 				/*
22657c478bd9Sstevel@tonic-gate 				 * Prefer router over hosts. Using hosts is a
22667c478bd9Sstevel@tonic-gate 				 * fallback mechanism, hence delete all host
22677c478bd9Sstevel@tonic-gate 				 * targets.
22687c478bd9Sstevel@tonic-gate 				 */
22697c478bd9Sstevel@tonic-gate 				while (pii->pii_targets != NULL)
22707c478bd9Sstevel@tonic-gate 					target_delete(pii->pii_targets);
22717c478bd9Sstevel@tonic-gate 			}
22727c478bd9Sstevel@tonic-gate 		} else {
22737c478bd9Sstevel@tonic-gate 			/*
22747c478bd9Sstevel@tonic-gate 			 * Routers take precedence over hosts. If this
22757c478bd9Sstevel@tonic-gate 			 * is a router list and we are trying to add a
22767c478bd9Sstevel@tonic-gate 			 * host, just return. If this is a host list
22777c478bd9Sstevel@tonic-gate 			 * and if we have sufficient targets, just return
22787c478bd9Sstevel@tonic-gate 			 */
22797c478bd9Sstevel@tonic-gate 			if (pii->pii_targets_are_routers ||
22807c478bd9Sstevel@tonic-gate 			    pii->pii_ntargets == MAX_PROBE_TARGETS)
22817c478bd9Sstevel@tonic-gate 				return;
22827c478bd9Sstevel@tonic-gate 		}
22837c478bd9Sstevel@tonic-gate 	}
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate 	tg = calloc(1, sizeof (struct target));
22867c478bd9Sstevel@tonic-gate 	if (tg == NULL) {
22877c478bd9Sstevel@tonic-gate 		logperror("target_create: calloc");
22887c478bd9Sstevel@tonic-gate 		return;
22897c478bd9Sstevel@tonic-gate 	}
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 	tg->tg_phyint_inst = pii;
22927c478bd9Sstevel@tonic-gate 	tg->tg_address = addr;
22937c478bd9Sstevel@tonic-gate 	tg->tg_in_use = 1;
22947c478bd9Sstevel@tonic-gate 	tg->tg_rtt_sa = -1;
22957c478bd9Sstevel@tonic-gate 	tg->tg_num_deferred = 0;
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 	/*
22987c478bd9Sstevel@tonic-gate 	 * If this is the first target, set 'pii_targets_are_routers'
22997c478bd9Sstevel@tonic-gate 	 * The list of targets is either a list of hosts or list or
23007c478bd9Sstevel@tonic-gate 	 * routers, but not a mix.
23017c478bd9Sstevel@tonic-gate 	 */
23027c478bd9Sstevel@tonic-gate 	if (pii->pii_targets == NULL) {
23037c478bd9Sstevel@tonic-gate 		assert(pii->pii_ntargets == 0);
23047c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next == NULL);
23057c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next == NULL);
23067c478bd9Sstevel@tonic-gate 		pii->pii_targets_are_routers = is_router ? 1 : 0;
23077c478bd9Sstevel@tonic-gate 	}
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 	if (pii->pii_ntargets == MAX_PROBE_TARGETS) {
23107c478bd9Sstevel@tonic-gate 		assert(pii->pii_targets_are_routers);
23117c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next != NULL);
23127c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next != NULL);
23137c478bd9Sstevel@tonic-gate 		tg->tg_status = TG_UNUSED;
23147c478bd9Sstevel@tonic-gate 	} else {
23157c478bd9Sstevel@tonic-gate 		if (pii->pii_ntargets == 0) {
23167c478bd9Sstevel@tonic-gate 			assert(pii->pii_target_next == NULL);
23177c478bd9Sstevel@tonic-gate 			pii->pii_target_next = tg;
23187c478bd9Sstevel@tonic-gate 			pii->pii_rtt_target_next = tg;
23197c478bd9Sstevel@tonic-gate 		}
23207c478bd9Sstevel@tonic-gate 		pii->pii_ntargets++;
23217c478bd9Sstevel@tonic-gate 		tg->tg_status = TG_ACTIVE;
23227c478bd9Sstevel@tonic-gate 	}
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 	target_insert(pii, tg);
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 	/*
2327921e7e07Smeem 	 * Change state to PI_RUNNING if this phyint instance is capable of
2328921e7e07Smeem 	 * sending and receiving probes -- that is, if we know of at least 1
2329921e7e07Smeem 	 * target, and this phyint instance is probe-capable.  For more
2330921e7e07Smeem 	 * details, see the phyint state diagram in mpd_probe.c.
23317c478bd9Sstevel@tonic-gate 	 */
23327c478bd9Sstevel@tonic-gate 	pi = pii->pii_phyint;
23337c478bd9Sstevel@tonic-gate 	if (pi->pi_state == PI_NOTARGETS && PROBE_CAPABLE(pii)) {
23347c478bd9Sstevel@tonic-gate 		if (pi->pi_flags & IFF_FAILED)
23357c478bd9Sstevel@tonic-gate 			phyint_chstate(pi, PI_FAILED);
23367c478bd9Sstevel@tonic-gate 		else
23377c478bd9Sstevel@tonic-gate 			phyint_chstate(pi, PI_RUNNING);
23387c478bd9Sstevel@tonic-gate 	}
23397c478bd9Sstevel@tonic-gate }
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate /*
23427c478bd9Sstevel@tonic-gate  * Add the target address named by `addr' to phyint instance `pii' if it does
23437c478bd9Sstevel@tonic-gate  * not already exist.  If the target is a router, `is_router' should be set to
23447c478bd9Sstevel@tonic-gate  * B_TRUE.
23457c478bd9Sstevel@tonic-gate  */
23467c478bd9Sstevel@tonic-gate void
target_add(struct phyint_instance * pii,struct in6_addr addr,boolean_t is_router)23477c478bd9Sstevel@tonic-gate target_add(struct phyint_instance *pii, struct in6_addr addr,
23487c478bd9Sstevel@tonic-gate     boolean_t is_router)
23497c478bd9Sstevel@tonic-gate {
23507c478bd9Sstevel@tonic-gate 	struct target *tg;
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 	if (pii == NULL)
23537c478bd9Sstevel@tonic-gate 		return;
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	tg = target_lookup(pii, addr);
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate 	/*
23587c478bd9Sstevel@tonic-gate 	 * If the target does not exist, create it; target_create() will set
2359e11c3f44Smeem 	 * tg_in_use to true.  Even if it exists already, if it's a router
2360e11c3f44Smeem 	 * target and we'd previously learned of it through multicast, then we
2361e11c3f44Smeem 	 * need to recreate it as a router target.  Otherwise, just set
2362e11c3f44Smeem 	 * tg_in_use to to true so that init_router_targets() won't delete it.
23637c478bd9Sstevel@tonic-gate 	 */
2364e11c3f44Smeem 	if (tg == NULL || (is_router && !pii->pii_targets_are_routers))
23657c478bd9Sstevel@tonic-gate 		target_create(pii, addr, is_router);
23667c478bd9Sstevel@tonic-gate 	else if (is_router)
23677c478bd9Sstevel@tonic-gate 		tg->tg_in_use = 1;
23687c478bd9Sstevel@tonic-gate }
23697c478bd9Sstevel@tonic-gate 
23707c478bd9Sstevel@tonic-gate /*
23717c478bd9Sstevel@tonic-gate  * Insert target at head of linked list of targets for the associated
23727c478bd9Sstevel@tonic-gate  * phyint instance
23737c478bd9Sstevel@tonic-gate  */
23747c478bd9Sstevel@tonic-gate static void
target_insert(struct phyint_instance * pii,struct target * tg)23757c478bd9Sstevel@tonic-gate target_insert(struct phyint_instance *pii, struct target *tg)
23767c478bd9Sstevel@tonic-gate {
23777c478bd9Sstevel@tonic-gate 	tg->tg_next = pii->pii_targets;
23787c478bd9Sstevel@tonic-gate 	tg->tg_prev = NULL;
23797c478bd9Sstevel@tonic-gate 	if (tg->tg_next != NULL)
23807c478bd9Sstevel@tonic-gate 		tg->tg_next->tg_prev = tg;
23817c478bd9Sstevel@tonic-gate 	pii->pii_targets = tg;
23827c478bd9Sstevel@tonic-gate }
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate /*
23857c478bd9Sstevel@tonic-gate  * Delete a target (unlink and free).
23867c478bd9Sstevel@tonic-gate  */
23877c478bd9Sstevel@tonic-gate void
target_delete(struct target * tg)23887c478bd9Sstevel@tonic-gate target_delete(struct target *tg)
23897c478bd9Sstevel@tonic-gate {
23907c478bd9Sstevel@tonic-gate 	int af;
23917c478bd9Sstevel@tonic-gate 	struct phyint_instance	*pii;
23927c478bd9Sstevel@tonic-gate 	struct phyint_instance	*pii_other;
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 	pii = tg->tg_phyint_inst;
23957c478bd9Sstevel@tonic-gate 	af = pii->pii_af;
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET) {
23987c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
23997c478bd9Sstevel@tonic-gate 
24007c478bd9Sstevel@tonic-gate 		logdebug("target_delete(%s %s, %s)\n",
24017c478bd9Sstevel@tonic-gate 		    AF_STR(af), pii->pii_name,
24027c478bd9Sstevel@tonic-gate 		    pr_addr(af, tg->tg_address, abuf, sizeof (abuf)));
24037c478bd9Sstevel@tonic-gate 	}
24047c478bd9Sstevel@tonic-gate 
24057c478bd9Sstevel@tonic-gate 	/*
24067c478bd9Sstevel@tonic-gate 	 * Target must be in the list of targets for this phyint
24077c478bd9Sstevel@tonic-gate 	 * instance.
24087c478bd9Sstevel@tonic-gate 	 */
24097c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets == tg || tg->tg_prev != NULL);
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate 	/*
24127c478bd9Sstevel@tonic-gate 	 * Reset all references to 'tg' in the probe information
24137c478bd9Sstevel@tonic-gate 	 * for this phyint.
24147c478bd9Sstevel@tonic-gate 	 */
24157c478bd9Sstevel@tonic-gate 	reset_pii_probes(pii, tg);
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate 	/*
24187c478bd9Sstevel@tonic-gate 	 * Remove this target from the list of targets of this
24197c478bd9Sstevel@tonic-gate 	 * phyint instance.
24207c478bd9Sstevel@tonic-gate 	 */
24217c478bd9Sstevel@tonic-gate 	if (tg->tg_prev == NULL) {
24227c478bd9Sstevel@tonic-gate 		pii->pii_targets = tg->tg_next;
24237c478bd9Sstevel@tonic-gate 	} else {
24247c478bd9Sstevel@tonic-gate 		tg->tg_prev->tg_next = tg->tg_next;
24257c478bd9Sstevel@tonic-gate 	}
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate 	if (tg->tg_next != NULL)
24287c478bd9Sstevel@tonic-gate 		tg->tg_next->tg_prev = tg->tg_prev;
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 	tg->tg_next = NULL;
24317c478bd9Sstevel@tonic-gate 	tg->tg_prev = NULL;
24327c478bd9Sstevel@tonic-gate 
24337c478bd9Sstevel@tonic-gate 	if (tg->tg_status == TG_ACTIVE)
24347c478bd9Sstevel@tonic-gate 		pii->pii_ntargets--;
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	/*
24377c478bd9Sstevel@tonic-gate 	 * Adjust the next target to probe, if it points to
24387c478bd9Sstevel@tonic-gate 	 * to the currently deleted target.
24397c478bd9Sstevel@tonic-gate 	 */
24407c478bd9Sstevel@tonic-gate 	if (pii->pii_target_next == tg)
24417c478bd9Sstevel@tonic-gate 		pii->pii_target_next = target_first(pii);
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	if (pii->pii_rtt_target_next == tg)
24447c478bd9Sstevel@tonic-gate 		pii->pii_rtt_target_next = target_first(pii);
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate 	free(tg);
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 	/*
24497c478bd9Sstevel@tonic-gate 	 * The number of active targets pii_ntargets == 0 iff
24507c478bd9Sstevel@tonic-gate 	 * the next active target pii->pii_target_next == NULL
24517c478bd9Sstevel@tonic-gate 	 */
24527c478bd9Sstevel@tonic-gate 	if (pii->pii_ntargets != 0) {
24537c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next != NULL);
24547c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next != NULL);
24557c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next->tg_status == TG_ACTIVE);
24567c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next->tg_status == TG_ACTIVE);
24577c478bd9Sstevel@tonic-gate 		return;
24587c478bd9Sstevel@tonic-gate 	}
24597c478bd9Sstevel@tonic-gate 
24607c478bd9Sstevel@tonic-gate 	/* At this point, we don't have any active targets. */
24617c478bd9Sstevel@tonic-gate 	assert(pii->pii_target_next == NULL);
24627c478bd9Sstevel@tonic-gate 	assert(pii->pii_rtt_target_next == NULL);
24637c478bd9Sstevel@tonic-gate 
24647c478bd9Sstevel@tonic-gate 	if (pii->pii_targets_are_routers) {
24657c478bd9Sstevel@tonic-gate 		/*
24667c478bd9Sstevel@tonic-gate 		 * Activate any TG_SLOW or TG_DEAD router targets,
24677c478bd9Sstevel@tonic-gate 		 * since we don't have any other targets
24687c478bd9Sstevel@tonic-gate 		 */
24697c478bd9Sstevel@tonic-gate 		target_activate_all(pii);
24707c478bd9Sstevel@tonic-gate 
24717c478bd9Sstevel@tonic-gate 		if (pii->pii_ntargets != 0) {
24727c478bd9Sstevel@tonic-gate 			assert(pii->pii_target_next != NULL);
24737c478bd9Sstevel@tonic-gate 			assert(pii->pii_rtt_target_next != NULL);
24747c478bd9Sstevel@tonic-gate 			assert(pii->pii_target_next->tg_status == TG_ACTIVE);
24757c478bd9Sstevel@tonic-gate 			assert(pii->pii_rtt_target_next->tg_status ==
24767c478bd9Sstevel@tonic-gate 			    TG_ACTIVE);
24777c478bd9Sstevel@tonic-gate 			return;
24787c478bd9Sstevel@tonic-gate 		}
24797c478bd9Sstevel@tonic-gate 	}
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate 	/*
24827c478bd9Sstevel@tonic-gate 	 * If we still don't have any active targets, the list must
24837c478bd9Sstevel@tonic-gate 	 * must be really empty. There aren't even TG_SLOW or TG_DEAD
24847c478bd9Sstevel@tonic-gate 	 * targets. Zero out the probe stats since it will not be
24857c478bd9Sstevel@tonic-gate 	 * relevant any longer.
24867c478bd9Sstevel@tonic-gate 	 */
24877c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets == NULL);
2488e11c3f44Smeem 	pii->pii_targets_are_routers = _B_FALSE;
24897c478bd9Sstevel@tonic-gate 	clear_pii_probe_stats(pii);
24907c478bd9Sstevel@tonic-gate 	pii_other = phyint_inst_other(pii);
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 	/*
2493e11c3f44Smeem 	 * If there are no targets on both instances and the interface would
2494e11c3f44Smeem 	 * otherwise be considered PI_RUNNING, go back to PI_NOTARGETS state,
2495e11c3f44Smeem 	 * since we cannot probe this phyint any more.  For more details,
2496e11c3f44Smeem 	 * please see phyint state diagram in mpd_probe.c.
24977c478bd9Sstevel@tonic-gate 	 */
2498e11c3f44Smeem 	if (!PROBE_CAPABLE(pii_other) && LINK_UP(pii->pii_phyint) &&
2499e6ed03fcSmeem 	    pii->pii_phyint->pi_state != PI_OFFLINE)
25007c478bd9Sstevel@tonic-gate 		phyint_chstate(pii->pii_phyint, PI_NOTARGETS);
25017c478bd9Sstevel@tonic-gate }
25027c478bd9Sstevel@tonic-gate 
25037c478bd9Sstevel@tonic-gate /*
25047c478bd9Sstevel@tonic-gate  * Flush the target list of every phyint in the group, if the list
25057c478bd9Sstevel@tonic-gate  * is a host target list. This is called if group failure is suspected.
25067c478bd9Sstevel@tonic-gate  * If all targets have failed, multicast will subsequently discover new
25077c478bd9Sstevel@tonic-gate  * targets. Else it is a group failure.
25087c478bd9Sstevel@tonic-gate  * Note: This function is a no-op if the list is a router target list.
25097c478bd9Sstevel@tonic-gate  */
25107c478bd9Sstevel@tonic-gate static void
target_flush_hosts(struct phyint_group * pg)25117c478bd9Sstevel@tonic-gate target_flush_hosts(struct phyint_group *pg)
25127c478bd9Sstevel@tonic-gate {
25137c478bd9Sstevel@tonic-gate 	struct phyint *pi;
25147c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
25157c478bd9Sstevel@tonic-gate 
25167c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET)
25177c478bd9Sstevel@tonic-gate 		logdebug("target_flush_hosts(%s)\n", pg->pg_name);
25187c478bd9Sstevel@tonic-gate 
25197c478bd9Sstevel@tonic-gate 	for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext) {
25207c478bd9Sstevel@tonic-gate 		pii = pi->pi_v4;
25217c478bd9Sstevel@tonic-gate 		if (pii != NULL && !pii->pii_targets_are_routers) {
25227c478bd9Sstevel@tonic-gate 			/*
25237c478bd9Sstevel@tonic-gate 			 * Delete all the targets. When the list becomes
25247c478bd9Sstevel@tonic-gate 			 * empty, target_delete() will set pii->pii_targets
25257c478bd9Sstevel@tonic-gate 			 * to NULL.
25267c478bd9Sstevel@tonic-gate 			 */
25277c478bd9Sstevel@tonic-gate 			while (pii->pii_targets != NULL)
25287c478bd9Sstevel@tonic-gate 				target_delete(pii->pii_targets);
25297c478bd9Sstevel@tonic-gate 		}
25307c478bd9Sstevel@tonic-gate 		pii = pi->pi_v6;
25317c478bd9Sstevel@tonic-gate 		if (pii != NULL && !pii->pii_targets_are_routers) {
25327c478bd9Sstevel@tonic-gate 			/*
25337c478bd9Sstevel@tonic-gate 			 * Delete all the targets. When the list becomes
25347c478bd9Sstevel@tonic-gate 			 * empty, target_delete() will set pii->pii_targets
25357c478bd9Sstevel@tonic-gate 			 * to NULL.
25367c478bd9Sstevel@tonic-gate 			 */
25377c478bd9Sstevel@tonic-gate 			while (pii->pii_targets != NULL)
25387c478bd9Sstevel@tonic-gate 				target_delete(pii->pii_targets);
25397c478bd9Sstevel@tonic-gate 		}
25407c478bd9Sstevel@tonic-gate 	}
25417c478bd9Sstevel@tonic-gate }
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate /*
25447c478bd9Sstevel@tonic-gate  * Reset all references to 'target' in the probe info, as this target is
25457c478bd9Sstevel@tonic-gate  * being deleted. The pr_target field is guaranteed to be non-null if
25467c478bd9Sstevel@tonic-gate  * pr_status is PR_UNACKED. So we change the pr_status to PR_LOST, so that
25477c478bd9Sstevel@tonic-gate  * pr_target will not be accessed unconditionally.
25487c478bd9Sstevel@tonic-gate  */
25497c478bd9Sstevel@tonic-gate static void
reset_pii_probes(struct phyint_instance * pii,struct target * tg)25507c478bd9Sstevel@tonic-gate reset_pii_probes(struct phyint_instance *pii, struct target *tg)
25517c478bd9Sstevel@tonic-gate {
25527c478bd9Sstevel@tonic-gate 	int i;
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	for (i = 0; i < PROBE_STATS_COUNT; i++) {
25557c478bd9Sstevel@tonic-gate 		if (pii->pii_probes[i].pr_target == tg) {
2556e11c3f44Smeem 			if (pii->pii_probes[i].pr_status == PR_UNACKED) {
2557e11c3f44Smeem 				probe_chstate(&pii->pii_probes[i], pii,
2558e11c3f44Smeem 				    PR_LOST);
2559e11c3f44Smeem 			}
25607c478bd9Sstevel@tonic-gate 			pii->pii_probes[i].pr_target = NULL;
25617c478bd9Sstevel@tonic-gate 		}
25627c478bd9Sstevel@tonic-gate 	}
25637c478bd9Sstevel@tonic-gate }
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate /*
25667c478bd9Sstevel@tonic-gate  * Clear the probe statistics array.
25677c478bd9Sstevel@tonic-gate  */
25687c478bd9Sstevel@tonic-gate void
clear_pii_probe_stats(struct phyint_instance * pii)25697c478bd9Sstevel@tonic-gate clear_pii_probe_stats(struct phyint_instance *pii)
25707c478bd9Sstevel@tonic-gate {
25717c478bd9Sstevel@tonic-gate 	bzero(pii->pii_probes, sizeof (struct probe_stats) * PROBE_STATS_COUNT);
25727c478bd9Sstevel@tonic-gate 	/* Reset the next probe index in the probe stats array */
25737c478bd9Sstevel@tonic-gate 	pii->pii_probe_next = 0;
25747c478bd9Sstevel@tonic-gate }
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate static void
target_print(struct target * tg)25777c478bd9Sstevel@tonic-gate target_print(struct target *tg)
25787c478bd9Sstevel@tonic-gate {
25797c478bd9Sstevel@tonic-gate 	char	abuf[INET6_ADDRSTRLEN];
25807c478bd9Sstevel@tonic-gate 	char	buf[128];
25817c478bd9Sstevel@tonic-gate 	char	buf2[128];
25827c478bd9Sstevel@tonic-gate 	int	af;
25837c478bd9Sstevel@tonic-gate 	int	i;
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 	af = tg->tg_phyint_inst->pii_af;
25867c478bd9Sstevel@tonic-gate 
25877c478bd9Sstevel@tonic-gate 	logdebug("Target on %s %s addr %s\n"
2588e11c3f44Smeem 	    "status %d rtt_sa %lld rtt_sd %lld crtt %d tg_in_use %d\n",
25897c478bd9Sstevel@tonic-gate 	    AF_STR(af), tg->tg_phyint_inst->pii_name,
25907c478bd9Sstevel@tonic-gate 	    pr_addr(af, tg->tg_address, abuf, sizeof (abuf)),
25917c478bd9Sstevel@tonic-gate 	    tg->tg_status, tg->tg_rtt_sa, tg->tg_rtt_sd,
25927c478bd9Sstevel@tonic-gate 	    tg->tg_crtt, tg->tg_in_use);
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 	buf[0] = '\0';
25957c478bd9Sstevel@tonic-gate 	for (i = 0; i < tg->tg_num_deferred; i++) {
25967c478bd9Sstevel@tonic-gate 		(void) snprintf(buf2, sizeof (buf2), " %dms",
25977c478bd9Sstevel@tonic-gate 		    tg->tg_deferred[i]);
25987c478bd9Sstevel@tonic-gate 		(void) strlcat(buf, buf2, sizeof (buf));
25997c478bd9Sstevel@tonic-gate 	}
26007c478bd9Sstevel@tonic-gate 	logdebug("deferred rtts:%s\n", buf);
26017c478bd9Sstevel@tonic-gate }
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate void
phyint_inst_print_all(void)26047c478bd9Sstevel@tonic-gate phyint_inst_print_all(void)
26057c478bd9Sstevel@tonic-gate {
26067c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 	for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) {
26097c478bd9Sstevel@tonic-gate 		phyint_inst_print(pii);
26107c478bd9Sstevel@tonic-gate 	}
26117c478bd9Sstevel@tonic-gate }
26127c478bd9Sstevel@tonic-gate 
26137c478bd9Sstevel@tonic-gate /*
26147c478bd9Sstevel@tonic-gate  * Compare two prefixes that have the same prefix length.
26157c478bd9Sstevel@tonic-gate  * Fails if the prefix length is unreasonable.
26167c478bd9Sstevel@tonic-gate  */
2617e11c3f44Smeem boolean_t
prefix_equal(struct in6_addr p1,struct in6_addr p2,uint_t prefix_len)2618e11c3f44Smeem prefix_equal(struct in6_addr p1, struct in6_addr p2, uint_t prefix_len)
26197c478bd9Sstevel@tonic-gate {
26207c478bd9Sstevel@tonic-gate 	uchar_t mask;
26217c478bd9Sstevel@tonic-gate 	int j;
26227c478bd9Sstevel@tonic-gate 
2623e11c3f44Smeem 	if (prefix_len > IPV6_ABITS)
26247c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	for (j = 0; prefix_len > 8; prefix_len -= 8, j++)
26277c478bd9Sstevel@tonic-gate 		if (p1.s6_addr[j] != p2.s6_addr[j])
26287c478bd9Sstevel@tonic-gate 			return (_B_FALSE);
26297c478bd9Sstevel@tonic-gate 
26307c478bd9Sstevel@tonic-gate 	/* Make the N leftmost bits one */
26317c478bd9Sstevel@tonic-gate 	mask = 0xff << (8 - prefix_len);
26327c478bd9Sstevel@tonic-gate 	if ((p1.s6_addr[j] & mask) != (p2.s6_addr[j] & mask))
26337c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
26367c478bd9Sstevel@tonic-gate }
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate /*
2639e11c3f44Smeem  * Get the number of UP logints on phyint `pi'.
26407c478bd9Sstevel@tonic-gate  */
2641e11c3f44Smeem static int
logint_upcount(struct phyint * pi)26427c478bd9Sstevel@tonic-gate logint_upcount(struct phyint *pi)
26437c478bd9Sstevel@tonic-gate {
26447c478bd9Sstevel@tonic-gate 	struct	logint	*li;
26457c478bd9Sstevel@tonic-gate 	int count = 0;
26467c478bd9Sstevel@tonic-gate 
2647e11c3f44Smeem 	if (pi->pi_v4 != NULL) {
2648e11c3f44Smeem 		for (li = pi->pi_v4->pii_logint; li != NULL; li = li->li_next) {
2649e11c3f44Smeem 			if (li->li_flags & IFF_UP)
26507c478bd9Sstevel@tonic-gate 				count++;
26517c478bd9Sstevel@tonic-gate 		}
26527c478bd9Sstevel@tonic-gate 	}
26537c478bd9Sstevel@tonic-gate 
2654e11c3f44Smeem 	if (pi->pi_v6 != NULL) {
2655e11c3f44Smeem 		for (li = pi->pi_v6->pii_logint; li != NULL; li = li->li_next) {
2656e11c3f44Smeem 			if (li->li_flags & IFF_UP)
26577c478bd9Sstevel@tonic-gate 				count++;
26587c478bd9Sstevel@tonic-gate 		}
26597c478bd9Sstevel@tonic-gate 	}
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 	return (count);
26627c478bd9Sstevel@tonic-gate }
26637c478bd9Sstevel@tonic-gate 
26647c478bd9Sstevel@tonic-gate /*
26657c478bd9Sstevel@tonic-gate  * Get the phyint instance with the other (IPv4 / IPv6) protocol
26667c478bd9Sstevel@tonic-gate  */
26677c478bd9Sstevel@tonic-gate struct phyint_instance *
phyint_inst_other(struct phyint_instance * pii)26687c478bd9Sstevel@tonic-gate phyint_inst_other(struct phyint_instance *pii)
26697c478bd9Sstevel@tonic-gate {
26707c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET)
26717c478bd9Sstevel@tonic-gate 		return (pii->pii_phyint->pi_v6);
26727c478bd9Sstevel@tonic-gate 	else
26737c478bd9Sstevel@tonic-gate 		return (pii->pii_phyint->pi_v4);
26747c478bd9Sstevel@tonic-gate }
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate /*
2677e11c3f44Smeem  * Check whether a phyint is functioning.
2678e11c3f44Smeem  */
2679*9bea6098Smeem boolean_t
phyint_is_functioning(struct phyint * pi)2680e11c3f44Smeem phyint_is_functioning(struct phyint *pi)
2681e11c3f44Smeem {
2682e11c3f44Smeem 	if (pi->pi_state == PI_RUNNING)
2683e11c3f44Smeem 		return (_B_TRUE);
2684e11c3f44Smeem 	return (pi->pi_state == PI_NOTARGETS && !(pi->pi_flags & IFF_FAILED));
2685e11c3f44Smeem }
2686e11c3f44Smeem 
2687e11c3f44Smeem /*
2688e11c3f44Smeem  * Check whether a phyint is usable.
2689e11c3f44Smeem  */
2690*9bea6098Smeem boolean_t
phyint_is_usable(struct phyint * pi)2691e11c3f44Smeem phyint_is_usable(struct phyint *pi)
2692e11c3f44Smeem {
2693e11c3f44Smeem 	if (logint_upcount(pi) == 0)
2694e11c3f44Smeem 		return (_B_FALSE);
2695e11c3f44Smeem 	return (phyint_is_functioning(pi));
2696e11c3f44Smeem }
2697e11c3f44Smeem 
2698e11c3f44Smeem /*
26997c478bd9Sstevel@tonic-gate  * Post an EC_IPMP sysevent of subclass `subclass' and attributes `nvl'.
27007c478bd9Sstevel@tonic-gate  * Before sending the event, it prepends the current version of the IPMP
27017c478bd9Sstevel@tonic-gate  * sysevent API.  Returns 0 on success, -1 on failure (in either case,
27027c478bd9Sstevel@tonic-gate  * `nvl' is freed).
27037c478bd9Sstevel@tonic-gate  */
27047c478bd9Sstevel@tonic-gate static int
post_event(const char * subclass,nvlist_t * nvl)27057c478bd9Sstevel@tonic-gate post_event(const char *subclass, nvlist_t *nvl)
27067c478bd9Sstevel@tonic-gate {
2707e11c3f44Smeem 	static evchan_t *evchp = NULL;
27087c478bd9Sstevel@tonic-gate 
2709d8233146Smeem 	/*
2710e11c3f44Smeem 	 * Initialize the event channel if we haven't already done so.
2711d8233146Smeem 	 */
2712e11c3f44Smeem 	if (evchp == NULL) {
2713e11c3f44Smeem 		errno = sysevent_evc_bind(IPMP_EVENT_CHAN, &evchp, EVCH_CREAT);
2714e11c3f44Smeem 		if (errno != 0) {
2715e11c3f44Smeem 			logerr("cannot create event channel `%s': %s\n",
2716e11c3f44Smeem 			    IPMP_EVENT_CHAN, strerror(errno));
2717e11c3f44Smeem 			goto failed;
2718e11c3f44Smeem 		}
2719d8233146Smeem 	}
2720d8233146Smeem 
27217c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_EVENT_VERSION,
27227c478bd9Sstevel@tonic-gate 	    IPMP_EVENT_CUR_VERSION);
27237c478bd9Sstevel@tonic-gate 	if (errno != 0) {
27247c478bd9Sstevel@tonic-gate 		logerr("cannot create `%s' event: %s", subclass,
27257c478bd9Sstevel@tonic-gate 		    strerror(errno));
27267c478bd9Sstevel@tonic-gate 		goto failed;
27277c478bd9Sstevel@tonic-gate 	}
27287c478bd9Sstevel@tonic-gate 
2729e11c3f44Smeem 	errno = sysevent_evc_publish(evchp, EC_IPMP, subclass, "com.sun",
2730e11c3f44Smeem 	    "in.mpathd", nvl, EVCH_NOSLEEP);
2731e11c3f44Smeem 	if (errno != 0) {
27327c478bd9Sstevel@tonic-gate 		logerr("cannot send `%s' event: %s\n", subclass,
27337c478bd9Sstevel@tonic-gate 		    strerror(errno));
27347c478bd9Sstevel@tonic-gate 		goto failed;
27357c478bd9Sstevel@tonic-gate 	}
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
27387c478bd9Sstevel@tonic-gate 	return (0);
27397c478bd9Sstevel@tonic-gate failed:
27407c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
27417c478bd9Sstevel@tonic-gate 	return (-1);
27427c478bd9Sstevel@tonic-gate }
27437c478bd9Sstevel@tonic-gate 
27447c478bd9Sstevel@tonic-gate /*
27457c478bd9Sstevel@tonic-gate  * Return the external IPMP state associated with phyint `pi'.
27467c478bd9Sstevel@tonic-gate  */
27477c478bd9Sstevel@tonic-gate static ipmp_if_state_t
ifstate(struct phyint * pi)27487c478bd9Sstevel@tonic-gate ifstate(struct phyint *pi)
27497c478bd9Sstevel@tonic-gate {
27507c478bd9Sstevel@tonic-gate 	switch (pi->pi_state) {
2751fcdc8680Smeem 	case PI_INIT:
2752fcdc8680Smeem 		return (IPMP_IF_UNKNOWN);
2753fcdc8680Smeem 
27547c478bd9Sstevel@tonic-gate 	case PI_NOTARGETS:
2755e11c3f44Smeem 		if (pi->pi_flags & IFF_FAILED)
2756e11c3f44Smeem 			return (IPMP_IF_FAILED);
27577c478bd9Sstevel@tonic-gate 		return (IPMP_IF_UNKNOWN);
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate 	case PI_OFFLINE:
27607c478bd9Sstevel@tonic-gate 		return (IPMP_IF_OFFLINE);
27617c478bd9Sstevel@tonic-gate 
27627c478bd9Sstevel@tonic-gate 	case PI_FAILED:
27637c478bd9Sstevel@tonic-gate 		return (IPMP_IF_FAILED);
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 	case PI_RUNNING:
27667c478bd9Sstevel@tonic-gate 		return (IPMP_IF_OK);
27677c478bd9Sstevel@tonic-gate 	}
27687c478bd9Sstevel@tonic-gate 
27697c478bd9Sstevel@tonic-gate 	logerr("ifstate: unknown state %d; aborting\n", pi->pi_state);
27707c478bd9Sstevel@tonic-gate 	abort();
27717c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
27727c478bd9Sstevel@tonic-gate }
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate /*
27757c478bd9Sstevel@tonic-gate  * Return the external IPMP interface type associated with phyint `pi'.
27767c478bd9Sstevel@tonic-gate  */
27777c478bd9Sstevel@tonic-gate static ipmp_if_type_t
iftype(struct phyint * pi)27787c478bd9Sstevel@tonic-gate iftype(struct phyint *pi)
27797c478bd9Sstevel@tonic-gate {
27807c478bd9Sstevel@tonic-gate 	if (pi->pi_flags & IFF_STANDBY)
27817c478bd9Sstevel@tonic-gate 		return (IPMP_IF_STANDBY);
27827c478bd9Sstevel@tonic-gate 	else
27837c478bd9Sstevel@tonic-gate 		return (IPMP_IF_NORMAL);
27847c478bd9Sstevel@tonic-gate }
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate /*
2787e11c3f44Smeem  * Return the external IPMP link state associated with phyint `pi'.
2788e11c3f44Smeem  */
2789e11c3f44Smeem static ipmp_if_linkstate_t
iflinkstate(struct phyint * pi)2790e11c3f44Smeem iflinkstate(struct phyint *pi)
2791e11c3f44Smeem {
2792e11c3f44Smeem 	if (!(pi->pi_notes & (DL_NOTE_LINK_UP|DL_NOTE_LINK_DOWN)))
2793e11c3f44Smeem 		return (IPMP_LINK_UNKNOWN);
2794e11c3f44Smeem 
2795e11c3f44Smeem 	return (LINK_DOWN(pi) ? IPMP_LINK_DOWN : IPMP_LINK_UP);
2796e11c3f44Smeem }
2797e11c3f44Smeem 
2798e11c3f44Smeem /*
2799e11c3f44Smeem  * Return the external IPMP probe state associated with phyint `pi'.
2800e11c3f44Smeem  */
2801e11c3f44Smeem static ipmp_if_probestate_t
ifprobestate(struct phyint * pi)2802e11c3f44Smeem ifprobestate(struct phyint *pi)
2803e11c3f44Smeem {
2804e11c3f44Smeem 	if (!PROBE_ENABLED(pi->pi_v4) && !PROBE_ENABLED(pi->pi_v6))
2805e11c3f44Smeem 		return (IPMP_PROBE_DISABLED);
2806e11c3f44Smeem 
2807e11c3f44Smeem 	if (pi->pi_state == PI_FAILED)
2808e11c3f44Smeem 		return (IPMP_PROBE_FAILED);
2809e11c3f44Smeem 
2810e11c3f44Smeem 	if (!PROBE_CAPABLE(pi->pi_v4) && !PROBE_CAPABLE(pi->pi_v6))
2811e11c3f44Smeem 		return (IPMP_PROBE_UNKNOWN);
2812e11c3f44Smeem 
2813e11c3f44Smeem 	return (IPMP_PROBE_OK);
2814e11c3f44Smeem }
2815e11c3f44Smeem 
2816e11c3f44Smeem /*
2817e11c3f44Smeem  * Return the external IPMP target mode associated with phyint instance `pii'.
2818e11c3f44Smeem  */
2819e11c3f44Smeem static ipmp_if_targmode_t
iftargmode(struct phyint_instance * pii)2820e11c3f44Smeem iftargmode(struct phyint_instance *pii)
2821e11c3f44Smeem {
2822e11c3f44Smeem 	if (!PROBE_ENABLED(pii))
2823e11c3f44Smeem 		return (IPMP_TARG_DISABLED);
2824e11c3f44Smeem 	else if (pii->pii_targets_are_routers)
2825e11c3f44Smeem 		return (IPMP_TARG_ROUTES);
2826e11c3f44Smeem 	else
2827e11c3f44Smeem 		return (IPMP_TARG_MULTICAST);
2828e11c3f44Smeem }
2829e11c3f44Smeem 
2830e11c3f44Smeem /*
2831e11c3f44Smeem  * Return the external IPMP flags associated with phyint `pi'.
2832e11c3f44Smeem  */
2833e11c3f44Smeem static ipmp_if_flags_t
ifflags(struct phyint * pi)2834e11c3f44Smeem ifflags(struct phyint *pi)
2835e11c3f44Smeem {
2836e11c3f44Smeem 	ipmp_if_flags_t flags = 0;
2837e11c3f44Smeem 
2838e11c3f44Smeem 	if (logint_upcount(pi) == 0)
2839e11c3f44Smeem 		flags |= IPMP_IFFLAG_DOWN;
2840e11c3f44Smeem 	if (pi->pi_flags & IFF_INACTIVE)
2841e11c3f44Smeem 		flags |= IPMP_IFFLAG_INACTIVE;
2842e11c3f44Smeem 	if (pi->pi_hwaddrdup)
2843e11c3f44Smeem 		flags |= IPMP_IFFLAG_HWADDRDUP;
2844e11c3f44Smeem 	if (phyint_is_functioning(pi) && flags == 0)
2845e11c3f44Smeem 		flags |= IPMP_IFFLAG_ACTIVE;
2846e11c3f44Smeem 
2847e11c3f44Smeem 	return (flags);
2848e11c3f44Smeem }
2849e11c3f44Smeem 
2850e11c3f44Smeem /*
2851e11c3f44Smeem  * Store the test address used on phyint instance `pii' in `ssp'.  If there's
2852e11c3f44Smeem  * no test address, 0.0.0.0 is stored.
2853e11c3f44Smeem  */
2854e11c3f44Smeem static struct sockaddr_storage *
iftestaddr(struct phyint_instance * pii,struct sockaddr_storage * ssp)2855e11c3f44Smeem iftestaddr(struct phyint_instance *pii, struct sockaddr_storage *ssp)
2856e11c3f44Smeem {
2857e11c3f44Smeem 	if (PROBE_ENABLED(pii))
2858e11c3f44Smeem 		addr2storage(pii->pii_af, &pii->pii_probe_logint->li_addr, ssp);
2859e11c3f44Smeem 	else
2860e11c3f44Smeem 		addr2storage(AF_INET6, &in6addr_any, ssp);
2861e11c3f44Smeem 
2862e11c3f44Smeem 	return (ssp);
2863e11c3f44Smeem }
2864e11c3f44Smeem 
2865e11c3f44Smeem /*
28667c478bd9Sstevel@tonic-gate  * Return the external IPMP group state associated with phyint group `pg'.
28677c478bd9Sstevel@tonic-gate  */
28687c478bd9Sstevel@tonic-gate static ipmp_group_state_t
groupstate(struct phyint_group * pg)28697c478bd9Sstevel@tonic-gate groupstate(struct phyint_group *pg)
28707c478bd9Sstevel@tonic-gate {
2871e11c3f44Smeem 	switch (pg->pg_state) {
2872e11c3f44Smeem 	case PG_FAILED:
2873e11c3f44Smeem 		return (IPMP_GROUP_FAILED);
2874e11c3f44Smeem 	case PG_DEGRADED:
2875e11c3f44Smeem 		return (IPMP_GROUP_DEGRADED);
2876e11c3f44Smeem 	case PG_OK:
2877e11c3f44Smeem 		return (IPMP_GROUP_OK);
2878e11c3f44Smeem 	}
2879e11c3f44Smeem 
2880e11c3f44Smeem 	logerr("groupstate: unknown state %d; aborting\n", pg->pg_state);
2881e11c3f44Smeem 	abort();
2882e11c3f44Smeem 	/* NOTREACHED */
2883e11c3f44Smeem }
2884e11c3f44Smeem 
2885e11c3f44Smeem /*
2886e11c3f44Smeem  * Return the external IPMP probe state associated with probe `ps'.
2887e11c3f44Smeem  */
2888e11c3f44Smeem static ipmp_probe_state_t
probestate(struct probe_stats * ps)2889e11c3f44Smeem probestate(struct probe_stats *ps)
2890e11c3f44Smeem {
2891e11c3f44Smeem 	switch (ps->pr_status) {
2892e11c3f44Smeem 	case PR_UNUSED:
2893e11c3f44Smeem 	case PR_LOST:
2894e11c3f44Smeem 		return (IPMP_PROBE_LOST);
2895e11c3f44Smeem 	case PR_UNACKED:
2896e11c3f44Smeem 		return (IPMP_PROBE_SENT);
2897e11c3f44Smeem 	case PR_ACKED:
2898e11c3f44Smeem 		return (IPMP_PROBE_ACKED);
2899e11c3f44Smeem 	}
2900e11c3f44Smeem 
2901e11c3f44Smeem 	logerr("probestate: unknown state %d; aborting\n", ps->pr_status);
2902e11c3f44Smeem 	abort();
2903e11c3f44Smeem 	/* NOTREACHED */
2904e11c3f44Smeem }
2905e11c3f44Smeem 
2906e11c3f44Smeem /*
2907e11c3f44Smeem  * Generate an ESC_IPMP_PROBE_STATE sysevent for the probe described by `pr'
2908e11c3f44Smeem  * on phyint instance `pii'.  Returns 0 on success, -1 on failure.
2909e11c3f44Smeem  */
2910e11c3f44Smeem int
probe_state_event(struct probe_stats * pr,struct phyint_instance * pii)2911e11c3f44Smeem probe_state_event(struct probe_stats *pr, struct phyint_instance *pii)
2912e11c3f44Smeem {
2913e11c3f44Smeem 	nvlist_t *nvl;
2914e11c3f44Smeem 	hrtime_t proc_time = 0, recv_time = 0;
2915e11c3f44Smeem 	struct sockaddr_storage ss;
2916e11c3f44Smeem 	struct target *tg = pr->pr_target;
2917c61f3fa8Smeem 	int64_t rttavg, rttdev;
2918e11c3f44Smeem 
2919e11c3f44Smeem 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
2920e11c3f44Smeem 	if (errno != 0) {
2921e11c3f44Smeem 		logperror("cannot create `interface change' event");
2922e11c3f44Smeem 		return (-1);
2923e11c3f44Smeem 	}
2924e11c3f44Smeem 
2925e11c3f44Smeem 	errno = nvlist_add_uint32(nvl, IPMP_PROBE_ID, pr->pr_id);
2926e11c3f44Smeem 	if (errno != 0)
2927e11c3f44Smeem 		goto failed;
2928e11c3f44Smeem 
2929e11c3f44Smeem 	errno = nvlist_add_string(nvl, IPMP_IF_NAME, pii->pii_phyint->pi_name);
2930e11c3f44Smeem 	if (errno != 0)
2931e11c3f44Smeem 		goto failed;
2932e11c3f44Smeem 
2933e11c3f44Smeem 	errno = nvlist_add_uint32(nvl, IPMP_PROBE_STATE, probestate(pr));
2934e11c3f44Smeem 	if (errno != 0)
2935e11c3f44Smeem 		goto failed;
2936e11c3f44Smeem 
2937e11c3f44Smeem 	errno = nvlist_add_hrtime(nvl, IPMP_PROBE_START_TIME,
2938e11c3f44Smeem 	    pr->pr_hrtime_start);
2939e11c3f44Smeem 	if (errno != 0)
2940e11c3f44Smeem 		goto failed;
2941e11c3f44Smeem 
2942e11c3f44Smeem 	errno = nvlist_add_hrtime(nvl, IPMP_PROBE_SENT_TIME,
2943e11c3f44Smeem 	    pr->pr_hrtime_sent);
2944e11c3f44Smeem 	if (errno != 0)
2945e11c3f44Smeem 		goto failed;
2946e11c3f44Smeem 
2947e11c3f44Smeem 	if (pr->pr_status == PR_ACKED) {
2948e11c3f44Smeem 		recv_time = pr->pr_hrtime_ackrecv;
2949e11c3f44Smeem 		proc_time = pr->pr_hrtime_ackproc;
2950e11c3f44Smeem 	}
2951e11c3f44Smeem 
2952e11c3f44Smeem 	errno = nvlist_add_hrtime(nvl, IPMP_PROBE_ACKRECV_TIME, recv_time);
2953e11c3f44Smeem 	if (errno != 0)
2954e11c3f44Smeem 		goto failed;
2955e11c3f44Smeem 
2956e11c3f44Smeem 	errno = nvlist_add_hrtime(nvl, IPMP_PROBE_ACKPROC_TIME, proc_time);
2957e11c3f44Smeem 	if (errno != 0)
2958e11c3f44Smeem 		goto failed;
2959e11c3f44Smeem 
2960e11c3f44Smeem 	if (tg != NULL)
2961e11c3f44Smeem 		addr2storage(pii->pii_af, &tg->tg_address, &ss);
2962e11c3f44Smeem 	else
2963e11c3f44Smeem 		addr2storage(pii->pii_af, &in6addr_any, &ss);
2964e11c3f44Smeem 
2965e11c3f44Smeem 	errno = nvlist_add_byte_array(nvl, IPMP_PROBE_TARGET, (uchar_t *)&ss,
2966e11c3f44Smeem 	    sizeof (ss));
2967e11c3f44Smeem 	if (errno != 0)
2968e11c3f44Smeem 		goto failed;
2969e11c3f44Smeem 
2970c61f3fa8Smeem 	rttavg = (tg != NULL) ? (tg->tg_rtt_sa / 8) : 0;
2971c61f3fa8Smeem 	errno = nvlist_add_int64(nvl, IPMP_PROBE_TARGET_RTTAVG, rttavg);
2972e11c3f44Smeem 	if (errno != 0)
2973e11c3f44Smeem 		goto failed;
2974e11c3f44Smeem 
2975c61f3fa8Smeem 	rttdev = (tg != NULL) ? (tg->tg_rtt_sd / 4) : 0;
2976c61f3fa8Smeem 	errno = nvlist_add_int64(nvl, IPMP_PROBE_TARGET_RTTDEV, rttdev);
2977e11c3f44Smeem 	if (errno != 0)
2978e11c3f44Smeem 		goto failed;
2979e11c3f44Smeem 
2980e11c3f44Smeem 	return (post_event(ESC_IPMP_PROBE_STATE, nvl));
2981e11c3f44Smeem failed:
2982e11c3f44Smeem 	logperror("cannot create `probe state' event");
2983e11c3f44Smeem 	nvlist_free(nvl);
2984e11c3f44Smeem 	return (-1);
29857c478bd9Sstevel@tonic-gate }
29867c478bd9Sstevel@tonic-gate 
29877c478bd9Sstevel@tonic-gate /*
29887c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_GROUP_STATE sysevent for phyint group `pg'.
29897c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
29907c478bd9Sstevel@tonic-gate  */
29917c478bd9Sstevel@tonic-gate static int
phyint_group_state_event(struct phyint_group * pg)29927c478bd9Sstevel@tonic-gate phyint_group_state_event(struct phyint_group *pg)
29937c478bd9Sstevel@tonic-gate {
29947c478bd9Sstevel@tonic-gate 	nvlist_t	*nvl;
29957c478bd9Sstevel@tonic-gate 
29967c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
29977c478bd9Sstevel@tonic-gate 	if (errno != 0) {
29987c478bd9Sstevel@tonic-gate 		logperror("cannot create `group state change' event");
29997c478bd9Sstevel@tonic-gate 		return (-1);
30007c478bd9Sstevel@tonic-gate 	}
30017c478bd9Sstevel@tonic-gate 
30027c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
30037c478bd9Sstevel@tonic-gate 	if (errno != 0)
30047c478bd9Sstevel@tonic-gate 		goto failed;
30057c478bd9Sstevel@tonic-gate 
30067c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
30077c478bd9Sstevel@tonic-gate 	if (errno != 0)
30087c478bd9Sstevel@tonic-gate 		goto failed;
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_GROUP_STATE, groupstate(pg));
30117c478bd9Sstevel@tonic-gate 	if (errno != 0)
30127c478bd9Sstevel@tonic-gate 		goto failed;
30137c478bd9Sstevel@tonic-gate 
30147c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_GROUP_STATE, nvl));
30157c478bd9Sstevel@tonic-gate failed:
30167c478bd9Sstevel@tonic-gate 	logperror("cannot create `group state change' event");
30177c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
30187c478bd9Sstevel@tonic-gate 	return (-1);
30197c478bd9Sstevel@tonic-gate }
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate /*
30227c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_GROUP_CHANGE sysevent of type `op' for phyint group
30237c478bd9Sstevel@tonic-gate  * `pg'.  Returns 0 on success, -1 on failure.
30247c478bd9Sstevel@tonic-gate  */
30257c478bd9Sstevel@tonic-gate static int
phyint_group_change_event(struct phyint_group * pg,ipmp_group_op_t op)30267c478bd9Sstevel@tonic-gate phyint_group_change_event(struct phyint_group *pg, ipmp_group_op_t op)
30277c478bd9Sstevel@tonic-gate {
30287c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
30297c478bd9Sstevel@tonic-gate 
30307c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
30317c478bd9Sstevel@tonic-gate 	if (errno != 0) {
30327c478bd9Sstevel@tonic-gate 		logperror("cannot create `group change' event");
30337c478bd9Sstevel@tonic-gate 		return (-1);
30347c478bd9Sstevel@tonic-gate 	}
30357c478bd9Sstevel@tonic-gate 
30367c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
30377c478bd9Sstevel@tonic-gate 	if (errno != 0)
30387c478bd9Sstevel@tonic-gate 		goto failed;
30397c478bd9Sstevel@tonic-gate 
30407c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
30417c478bd9Sstevel@tonic-gate 	if (errno != 0)
30427c478bd9Sstevel@tonic-gate 		goto failed;
30437c478bd9Sstevel@tonic-gate 
30447c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUPLIST_SIGNATURE,
30457c478bd9Sstevel@tonic-gate 	    phyint_grouplistsig);
30467c478bd9Sstevel@tonic-gate 	if (errno != 0)
30477c478bd9Sstevel@tonic-gate 		goto failed;
30487c478bd9Sstevel@tonic-gate 
30497c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_GROUP_OPERATION, op);
30507c478bd9Sstevel@tonic-gate 	if (errno != 0)
30517c478bd9Sstevel@tonic-gate 		goto failed;
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_GROUP_CHANGE, nvl));
30547c478bd9Sstevel@tonic-gate failed:
30557c478bd9Sstevel@tonic-gate 	logperror("cannot create `group change' event");
30567c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
30577c478bd9Sstevel@tonic-gate 	return (-1);
30587c478bd9Sstevel@tonic-gate }
30597c478bd9Sstevel@tonic-gate 
30607c478bd9Sstevel@tonic-gate /*
30617c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_GROUP_MEMBER_CHANGE sysevent for phyint `pi' in
30627c478bd9Sstevel@tonic-gate  * group `pg'.	Returns 0 on success, -1 on failure.
30637c478bd9Sstevel@tonic-gate  */
30647c478bd9Sstevel@tonic-gate static int
phyint_group_member_event(struct phyint_group * pg,struct phyint * pi,ipmp_if_op_t op)30657c478bd9Sstevel@tonic-gate phyint_group_member_event(struct phyint_group *pg, struct phyint *pi,
30667c478bd9Sstevel@tonic-gate     ipmp_if_op_t op)
30677c478bd9Sstevel@tonic-gate {
30687c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
30697c478bd9Sstevel@tonic-gate 
30707c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
30717c478bd9Sstevel@tonic-gate 	if (errno != 0) {
30727c478bd9Sstevel@tonic-gate 		logperror("cannot create `group member change' event");
30737c478bd9Sstevel@tonic-gate 		return (-1);
30747c478bd9Sstevel@tonic-gate 	}
30757c478bd9Sstevel@tonic-gate 
30767c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
30777c478bd9Sstevel@tonic-gate 	if (errno != 0)
30787c478bd9Sstevel@tonic-gate 		goto failed;
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
30817c478bd9Sstevel@tonic-gate 	if (errno != 0)
30827c478bd9Sstevel@tonic-gate 		goto failed;
30837c478bd9Sstevel@tonic-gate 
30847c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_OPERATION, op);
30857c478bd9Sstevel@tonic-gate 	if (errno != 0)
30867c478bd9Sstevel@tonic-gate 		goto failed;
30877c478bd9Sstevel@tonic-gate 
30887c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_IF_NAME, pi->pi_name);
30897c478bd9Sstevel@tonic-gate 	if (errno != 0)
30907c478bd9Sstevel@tonic-gate 		goto failed;
30917c478bd9Sstevel@tonic-gate 
30927c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_TYPE, iftype(pi));
30937c478bd9Sstevel@tonic-gate 	if (errno != 0)
30947c478bd9Sstevel@tonic-gate 		goto failed;
30957c478bd9Sstevel@tonic-gate 
30967c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_STATE, ifstate(pi));
30977c478bd9Sstevel@tonic-gate 	if (errno != 0)
30987c478bd9Sstevel@tonic-gate 		goto failed;
30997c478bd9Sstevel@tonic-gate 
31007c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_GROUP_MEMBER_CHANGE, nvl));
31017c478bd9Sstevel@tonic-gate failed:
31027c478bd9Sstevel@tonic-gate 	logperror("cannot create `group member change' event");
31037c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
31047c478bd9Sstevel@tonic-gate 	return (-1);
31057c478bd9Sstevel@tonic-gate 
31067c478bd9Sstevel@tonic-gate }
31077c478bd9Sstevel@tonic-gate 
31087c478bd9Sstevel@tonic-gate /*
31097c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_IF_CHANGE sysevent for phyint `pi' in group `pg'.
31107c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
31117c478bd9Sstevel@tonic-gate  */
31127c478bd9Sstevel@tonic-gate static int
phyint_state_event(struct phyint_group * pg,struct phyint * pi)31137c478bd9Sstevel@tonic-gate phyint_state_event(struct phyint_group *pg, struct phyint *pi)
31147c478bd9Sstevel@tonic-gate {
31157c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
31167c478bd9Sstevel@tonic-gate 
31177c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
31187c478bd9Sstevel@tonic-gate 	if (errno != 0) {
31197c478bd9Sstevel@tonic-gate 		logperror("cannot create `interface change' event");
31207c478bd9Sstevel@tonic-gate 		return (-1);
31217c478bd9Sstevel@tonic-gate 	}
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
31247c478bd9Sstevel@tonic-gate 	if (errno != 0)
31257c478bd9Sstevel@tonic-gate 		goto failed;
31267c478bd9Sstevel@tonic-gate 
31277c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
31287c478bd9Sstevel@tonic-gate 	if (errno != 0)
31297c478bd9Sstevel@tonic-gate 		goto failed;
31307c478bd9Sstevel@tonic-gate 
31317c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_IF_NAME, pi->pi_name);
31327c478bd9Sstevel@tonic-gate 	if (errno != 0)
31337c478bd9Sstevel@tonic-gate 		goto failed;
31347c478bd9Sstevel@tonic-gate 
31357c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_TYPE, iftype(pi));
31367c478bd9Sstevel@tonic-gate 	if (errno != 0)
31377c478bd9Sstevel@tonic-gate 		goto failed;
31387c478bd9Sstevel@tonic-gate 
31397c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_STATE, ifstate(pi));
31407c478bd9Sstevel@tonic-gate 	if (errno != 0)
31417c478bd9Sstevel@tonic-gate 		goto failed;
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_IF_CHANGE, nvl));
31447c478bd9Sstevel@tonic-gate failed:
31457c478bd9Sstevel@tonic-gate 	logperror("cannot create `interface change' event");
31467c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
31477c478bd9Sstevel@tonic-gate 	return (-1);
31487c478bd9Sstevel@tonic-gate 
31497c478bd9Sstevel@tonic-gate }
31507c478bd9Sstevel@tonic-gate 
31517c478bd9Sstevel@tonic-gate /*
31527c478bd9Sstevel@tonic-gate  * Generate a signature for use.  The signature is conceptually divided
31537c478bd9Sstevel@tonic-gate  * into two pieces: a random 16-bit "generation number" and a 48-bit
31547c478bd9Sstevel@tonic-gate  * monotonically increasing integer.  The generation number protects
31557c478bd9Sstevel@tonic-gate  * against stale updates to entities (e.g., IPMP groups) that have been
31567c478bd9Sstevel@tonic-gate  * deleted and since recreated.
31577c478bd9Sstevel@tonic-gate  */
31587c478bd9Sstevel@tonic-gate static uint64_t
gensig(void)31597c478bd9Sstevel@tonic-gate gensig(void)
31607c478bd9Sstevel@tonic-gate {
31617c478bd9Sstevel@tonic-gate 	static int seeded = 0;
31627c478bd9Sstevel@tonic-gate 
31637c478bd9Sstevel@tonic-gate 	if (seeded == 0) {
31647c478bd9Sstevel@tonic-gate 		srand48((long)gethrtime());
31657c478bd9Sstevel@tonic-gate 		seeded++;
31667c478bd9Sstevel@tonic-gate 	}
31677c478bd9Sstevel@tonic-gate 
31687c478bd9Sstevel@tonic-gate 	return ((uint64_t)lrand48() << 48 | 1);
31697c478bd9Sstevel@tonic-gate }
31707c478bd9Sstevel@tonic-gate 
31717c478bd9Sstevel@tonic-gate /*
31727c478bd9Sstevel@tonic-gate  * Store the information associated with group `grname' into a dynamically
31737c478bd9Sstevel@tonic-gate  * allocated structure pointed to by `*grinfopp'.  Returns an IPMP error code.
31747c478bd9Sstevel@tonic-gate  */
31757c478bd9Sstevel@tonic-gate unsigned int
getgroupinfo(const char * grname,ipmp_groupinfo_t ** grinfopp)31767c478bd9Sstevel@tonic-gate getgroupinfo(const char *grname, ipmp_groupinfo_t **grinfopp)
31777c478bd9Sstevel@tonic-gate {
31787c478bd9Sstevel@tonic-gate 	struct phyint		*pi;
3179e11c3f44Smeem 	struct phyint_group	*pg;
31807c478bd9Sstevel@tonic-gate 	char			(*ifs)[LIFNAMSIZ];
3181e11c3f44Smeem 	unsigned int		i, j;
3182e11c3f44Smeem 	unsigned int		nif = 0, naddr = 0;
3183e11c3f44Smeem 	lifgroupinfo_t		lifgr;
3184e11c3f44Smeem 	addrlist_t		*addrp;
3185e11c3f44Smeem 	struct sockaddr_storage	*addrs;
3186e11c3f44Smeem 	int			fdt = 0;
31877c478bd9Sstevel@tonic-gate 
31887c478bd9Sstevel@tonic-gate 	pg = phyint_group_lookup(grname);
31897c478bd9Sstevel@tonic-gate 	if (pg == NULL)
31907c478bd9Sstevel@tonic-gate 		return (IPMP_EUNKGROUP);
31917c478bd9Sstevel@tonic-gate 
31927c478bd9Sstevel@tonic-gate 	/*
31937c478bd9Sstevel@tonic-gate 	 * Tally up the number of interfaces, allocate an array to hold them,
3194e11c3f44Smeem 	 * and insert their names into the array.  While we're at it, if any
3195e11c3f44Smeem 	 * interface is actually enabled to send probes, save the group fdt.
31967c478bd9Sstevel@tonic-gate 	 */
3197e11c3f44Smeem 	for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext)
31987c478bd9Sstevel@tonic-gate 		nif++;
31997c478bd9Sstevel@tonic-gate 
32007c478bd9Sstevel@tonic-gate 	ifs = alloca(nif * sizeof (*ifs));
32017c478bd9Sstevel@tonic-gate 	for (i = 0, pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext, i++) {
32027c478bd9Sstevel@tonic-gate 		assert(i < nif);
32037c478bd9Sstevel@tonic-gate 		(void) strlcpy(ifs[i], pi->pi_name, LIFNAMSIZ);
3204e11c3f44Smeem 		if (PROBE_ENABLED(pi->pi_v4) || PROBE_ENABLED(pi->pi_v6))
3205e11c3f44Smeem 			fdt = pg->pg_fdt;
32067c478bd9Sstevel@tonic-gate 	}
32077c478bd9Sstevel@tonic-gate 	assert(i == nif);
32087c478bd9Sstevel@tonic-gate 
3209e11c3f44Smeem 	/*
3210e11c3f44Smeem 	 * If this is the anonymous group, there's no other information to
3211e11c3f44Smeem 	 * collect (since there's no IPMP interface).
3212e11c3f44Smeem 	 */
3213e11c3f44Smeem 	if (pg == phyint_anongroup) {
3214e11c3f44Smeem 		*grinfopp = ipmp_groupinfo_create(pg->pg_name, pg->pg_sig, fdt,
3215e11c3f44Smeem 		    groupstate(pg), nif, ifs, "", "", "", "", 0, NULL);
32167c478bd9Sstevel@tonic-gate 		return (*grinfopp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
32177c478bd9Sstevel@tonic-gate 	}
32187c478bd9Sstevel@tonic-gate 
32197c478bd9Sstevel@tonic-gate 	/*
3220e11c3f44Smeem 	 * Grab some additional information about the group from the kernel.
3221e11c3f44Smeem 	 * (NOTE: since SIOCGLIFGROUPINFO does not look up by interface name,
3222e11c3f44Smeem 	 * we can use ifsock_v4 even for a V6-only group.)
3223e11c3f44Smeem 	 */
3224e11c3f44Smeem 	(void) strlcpy(lifgr.gi_grname, grname, LIFGRNAMSIZ);
3225e11c3f44Smeem 	if (ioctl(ifsock_v4, SIOCGLIFGROUPINFO, &lifgr) == -1) {
3226e11c3f44Smeem 		if (errno == ENOENT)
3227e11c3f44Smeem 			return (IPMP_EUNKGROUP);
3228e11c3f44Smeem 
3229e11c3f44Smeem 		logperror("getgroupinfo: SIOCGLIFGROUPINFO");
3230e11c3f44Smeem 		return (IPMP_FAILURE);
3231e11c3f44Smeem 	}
3232e11c3f44Smeem 
3233e11c3f44Smeem 	/*
3234e11c3f44Smeem 	 * Tally up the number of data addresses, allocate an array to hold
3235e11c3f44Smeem 	 * them, and insert their values into the array.
3236e11c3f44Smeem 	 */
3237e11c3f44Smeem 	for (addrp = pg->pg_addrs; addrp != NULL; addrp = addrp->al_next)
3238e11c3f44Smeem 		naddr++;
3239e11c3f44Smeem 
3240e11c3f44Smeem 	addrs = alloca(naddr * sizeof (*addrs));
3241e11c3f44Smeem 	i = 0;
3242e11c3f44Smeem 	for (addrp = pg->pg_addrs; addrp != NULL; addrp = addrp->al_next) {
3243e11c3f44Smeem 		/*
3244e11c3f44Smeem 		 * It's possible to have duplicate addresses (if some are
3245e11c3f44Smeem 		 * down).  Weed the dups out to avoid confusing consumers.
3246e11c3f44Smeem 		 * (If groups start having tons of addresses, we'll need a
3247e11c3f44Smeem 		 * better algorithm here.)
3248e11c3f44Smeem 		 */
3249e11c3f44Smeem 		for (j = 0; j < i; j++) {
3250e11c3f44Smeem 			if (sockaddrcmp(&addrs[j], &addrp->al_addr))
3251e11c3f44Smeem 				break;
3252e11c3f44Smeem 		}
3253e11c3f44Smeem 		if (j == i) {
3254e11c3f44Smeem 			assert(i < naddr);
3255e11c3f44Smeem 			addrs[i++] = addrp->al_addr;
3256e11c3f44Smeem 		}
3257e11c3f44Smeem 	}
3258e11c3f44Smeem 	naddr = i;
3259e11c3f44Smeem 
3260e11c3f44Smeem 	*grinfopp = ipmp_groupinfo_create(pg->pg_name, pg->pg_sig, fdt,
3261e11c3f44Smeem 	    groupstate(pg), nif, ifs, lifgr.gi_grifname, lifgr.gi_m4ifname,
3262e11c3f44Smeem 	    lifgr.gi_m6ifname, lifgr.gi_bcifname, naddr, addrs);
3263e11c3f44Smeem 	return (*grinfopp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
3264e11c3f44Smeem }
3265e11c3f44Smeem 
3266e11c3f44Smeem /*
3267e11c3f44Smeem  * Store the target information associated with phyint instance `pii' into a
3268e11c3f44Smeem  * dynamically allocated structure pointed to by `*targinfopp'.  Returns an
3269e11c3f44Smeem  * IPMP error code.
3270e11c3f44Smeem  */
3271e11c3f44Smeem unsigned int
gettarginfo(struct phyint_instance * pii,const char * name,ipmp_targinfo_t ** targinfopp)3272e11c3f44Smeem gettarginfo(struct phyint_instance *pii, const char *name,
3273e11c3f44Smeem     ipmp_targinfo_t **targinfopp)
3274e11c3f44Smeem {
3275e11c3f44Smeem 	uint_t ntarg = 0;
3276e11c3f44Smeem 	struct target *tg;
3277e11c3f44Smeem 	struct sockaddr_storage	ss;
3278e11c3f44Smeem 	struct sockaddr_storage *targs = NULL;
3279e11c3f44Smeem 
3280e11c3f44Smeem 	if (PROBE_CAPABLE(pii)) {
3281e11c3f44Smeem 		targs = alloca(pii->pii_ntargets * sizeof (*targs));
3282e11c3f44Smeem 		tg = pii->pii_target_next;
3283e11c3f44Smeem 		do {
3284e11c3f44Smeem 			if (tg->tg_status == TG_ACTIVE) {
3285e11c3f44Smeem 				assert(ntarg < pii->pii_ntargets);
3286e11c3f44Smeem 				addr2storage(pii->pii_af, &tg->tg_address,
3287e11c3f44Smeem 				    &targs[ntarg++]);
3288e11c3f44Smeem 			}
3289e11c3f44Smeem 			if ((tg = tg->tg_next) == NULL)
3290e11c3f44Smeem 				tg = pii->pii_targets;
3291e11c3f44Smeem 		} while (tg != pii->pii_target_next);
3292e11c3f44Smeem 
3293e11c3f44Smeem 		assert(ntarg == pii->pii_ntargets);
3294e11c3f44Smeem 	}
3295e11c3f44Smeem 
3296e11c3f44Smeem 	*targinfopp = ipmp_targinfo_create(name, iftestaddr(pii, &ss),
3297e11c3f44Smeem 	    iftargmode(pii), ntarg, targs);
3298e11c3f44Smeem 	return (*targinfopp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
3299e11c3f44Smeem }
3300e11c3f44Smeem 
3301e11c3f44Smeem /*
33027c478bd9Sstevel@tonic-gate  * Store the information associated with interface `ifname' into a dynamically
33037c478bd9Sstevel@tonic-gate  * allocated structure pointed to by `*ifinfopp'.  Returns an IPMP error code.
33047c478bd9Sstevel@tonic-gate  */
33057c478bd9Sstevel@tonic-gate unsigned int
getifinfo(const char * ifname,ipmp_ifinfo_t ** ifinfopp)33067c478bd9Sstevel@tonic-gate getifinfo(const char *ifname, ipmp_ifinfo_t **ifinfopp)
33077c478bd9Sstevel@tonic-gate {
3308e11c3f44Smeem 	int		retval;
33097c478bd9Sstevel@tonic-gate 	struct phyint	*pi;
3310e11c3f44Smeem 	ipmp_targinfo_t	*targinfo4;
3311e11c3f44Smeem 	ipmp_targinfo_t	*targinfo6;
33127c478bd9Sstevel@tonic-gate 
33137c478bd9Sstevel@tonic-gate 	pi = phyint_lookup(ifname);
33147c478bd9Sstevel@tonic-gate 	if (pi == NULL)
33157c478bd9Sstevel@tonic-gate 		return (IPMP_EUNKIF);
33167c478bd9Sstevel@tonic-gate 
3317e11c3f44Smeem 	if ((retval = gettarginfo(pi->pi_v4, pi->pi_name, &targinfo4)) != 0 ||
3318e11c3f44Smeem 	    (retval = gettarginfo(pi->pi_v6, pi->pi_name, &targinfo6)) != 0)
3319e11c3f44Smeem 		goto out;
3320e11c3f44Smeem 
33217c478bd9Sstevel@tonic-gate 	*ifinfopp = ipmp_ifinfo_create(pi->pi_name, pi->pi_group->pg_name,
3322e11c3f44Smeem 	    ifstate(pi), iftype(pi), iflinkstate(pi), ifprobestate(pi),
3323e11c3f44Smeem 	    ifflags(pi), targinfo4, targinfo6);
3324e11c3f44Smeem 	retval = (*ifinfopp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
3325e11c3f44Smeem out:
3326e11c3f44Smeem 	if (targinfo4 != NULL)
3327e11c3f44Smeem 		ipmp_freetarginfo(targinfo4);
3328e11c3f44Smeem 	if (targinfo6 != NULL)
3329e11c3f44Smeem 		ipmp_freetarginfo(targinfo6);
3330e11c3f44Smeem 	return (retval);
33317c478bd9Sstevel@tonic-gate }
33327c478bd9Sstevel@tonic-gate 
33337c478bd9Sstevel@tonic-gate /*
33347c478bd9Sstevel@tonic-gate  * Store the current list of IPMP groups into a dynamically allocated
33357c478bd9Sstevel@tonic-gate  * structure pointed to by `*grlistpp'.	 Returns an IPMP error code.
33367c478bd9Sstevel@tonic-gate  */
33377c478bd9Sstevel@tonic-gate unsigned int
getgrouplist(ipmp_grouplist_t ** grlistpp)33387c478bd9Sstevel@tonic-gate getgrouplist(ipmp_grouplist_t **grlistpp)
33397c478bd9Sstevel@tonic-gate {
33407c478bd9Sstevel@tonic-gate 	struct phyint_group	*pg;
33417c478bd9Sstevel@tonic-gate 	char			(*groups)[LIFGRNAMSIZ];
33427c478bd9Sstevel@tonic-gate 	unsigned int		i, ngroup;
33437c478bd9Sstevel@tonic-gate 
33447c478bd9Sstevel@tonic-gate 	/*
33457c478bd9Sstevel@tonic-gate 	 * Tally up the number of groups, allocate an array to hold them, and
33467c478bd9Sstevel@tonic-gate 	 * insert their names into the array.
33477c478bd9Sstevel@tonic-gate 	 */
33487c478bd9Sstevel@tonic-gate 	for (ngroup = 0, pg = phyint_groups; pg != NULL; pg = pg->pg_next)
33497c478bd9Sstevel@tonic-gate 		ngroup++;
33507c478bd9Sstevel@tonic-gate 
33517c478bd9Sstevel@tonic-gate 	groups = alloca(ngroup * sizeof (*groups));
33527c478bd9Sstevel@tonic-gate 	for (i = 0, pg = phyint_groups; pg != NULL; pg = pg->pg_next, i++) {
33537c478bd9Sstevel@tonic-gate 		assert(i < ngroup);
33547c478bd9Sstevel@tonic-gate 		(void) strlcpy(groups[i], pg->pg_name, LIFGRNAMSIZ);
33557c478bd9Sstevel@tonic-gate 	}
33567c478bd9Sstevel@tonic-gate 	assert(i == ngroup);
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate 	*grlistpp = ipmp_grouplist_create(phyint_grouplistsig, ngroup, groups);
33597c478bd9Sstevel@tonic-gate 	return (*grlistpp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
33607c478bd9Sstevel@tonic-gate }
33617c478bd9Sstevel@tonic-gate 
33627c478bd9Sstevel@tonic-gate /*
3363e11c3f44Smeem  * Store the address information for `ssp' (in group `grname') into a
3364e11c3f44Smeem  * dynamically allocated structure pointed to by `*adinfopp'.  Returns an IPMP
3365e11c3f44Smeem  * error code.  (We'd call this function getaddrinfo(), but it would conflict
3366e11c3f44Smeem  * with getaddrinfo(3SOCKET)).
3367e11c3f44Smeem  */
3368e11c3f44Smeem unsigned int
getgraddrinfo(const char * grname,struct sockaddr_storage * ssp,ipmp_addrinfo_t ** adinfopp)3369e11c3f44Smeem getgraddrinfo(const char *grname, struct sockaddr_storage *ssp,
3370e11c3f44Smeem     ipmp_addrinfo_t **adinfopp)
3371e11c3f44Smeem {
3372e11c3f44Smeem 	int ifsock;
3373e11c3f44Smeem 	addrlist_t *addrp, *addrmatchp = NULL;
3374e11c3f44Smeem 	ipmp_addr_state_t state;
3375e11c3f44Smeem 	const char *binding = "";
3376e11c3f44Smeem 	struct lifreq lifr;
3377e11c3f44Smeem 	struct phyint_group *pg;
3378e11c3f44Smeem 
3379e11c3f44Smeem 	if ((pg = phyint_group_lookup(grname)) == NULL)
3380e11c3f44Smeem 		return (IPMP_EUNKADDR);
3381e11c3f44Smeem 
3382e11c3f44Smeem 	/*
3383e11c3f44Smeem 	 * Walk through the data addresses, and find a match.  Note that since
3384e11c3f44Smeem 	 * some of the addresses may be down, more than one may match.  We
3385e11c3f44Smeem 	 * prefer an up address (if one exists).
3386e11c3f44Smeem 	 */
3387e11c3f44Smeem 	for (addrp = pg->pg_addrs; addrp != NULL; addrp = addrp->al_next) {
3388e11c3f44Smeem 		if (sockaddrcmp(ssp, &addrp->al_addr)) {
3389e11c3f44Smeem 			addrmatchp = addrp;
3390e11c3f44Smeem 			if (addrmatchp->al_flags & IFF_UP)
3391e11c3f44Smeem 				break;
3392e11c3f44Smeem 		}
3393e11c3f44Smeem 	}
3394e11c3f44Smeem 
3395e11c3f44Smeem 	if (addrmatchp == NULL)
3396e11c3f44Smeem 		return (IPMP_EUNKADDR);
3397e11c3f44Smeem 
3398e11c3f44Smeem 	state = (addrmatchp->al_flags & IFF_UP) ? IPMP_ADDR_UP : IPMP_ADDR_DOWN;
3399e11c3f44Smeem 	if (state == IPMP_ADDR_UP) {
3400e11c3f44Smeem 		ifsock = (ssp->ss_family == AF_INET) ? ifsock_v4 : ifsock_v6;
3401e11c3f44Smeem 		(void) strlcpy(lifr.lifr_name, addrmatchp->al_name, LIFNAMSIZ);
3402e11c3f44Smeem 		if (ioctl(ifsock, SIOCGLIFBINDING, &lifr) >= 0)
3403e11c3f44Smeem 			binding = lifr.lifr_binding;
3404e11c3f44Smeem 	}
3405e11c3f44Smeem 
3406e11c3f44Smeem 	*adinfopp = ipmp_addrinfo_create(ssp, state, pg->pg_name, binding);
3407e11c3f44Smeem 	return (*adinfopp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
3408e11c3f44Smeem }
3409e11c3f44Smeem 
3410e11c3f44Smeem /*
34117c478bd9Sstevel@tonic-gate  * Store a snapshot of the IPMP subsystem into a dynamically allocated
34127c478bd9Sstevel@tonic-gate  * structure pointed to by `*snapp'.  Returns an IPMP error code.
34137c478bd9Sstevel@tonic-gate  */
34147c478bd9Sstevel@tonic-gate unsigned int
getsnap(ipmp_snap_t ** snapp)34157c478bd9Sstevel@tonic-gate getsnap(ipmp_snap_t **snapp)
34167c478bd9Sstevel@tonic-gate {
34177c478bd9Sstevel@tonic-gate 	ipmp_grouplist_t	*grlistp;
34187c478bd9Sstevel@tonic-gate 	ipmp_groupinfo_t	*grinfop;
3419e11c3f44Smeem 	ipmp_addrinfo_t		*adinfop;
3420e11c3f44Smeem 	ipmp_addrlist_t		*adlistp;
34217c478bd9Sstevel@tonic-gate 	ipmp_ifinfo_t		*ifinfop;
34227c478bd9Sstevel@tonic-gate 	ipmp_snap_t		*snap;
34237c478bd9Sstevel@tonic-gate 	struct phyint		*pi;
3424e11c3f44Smeem 	unsigned int		i, j;
34257c478bd9Sstevel@tonic-gate 	int			retval;
34267c478bd9Sstevel@tonic-gate 
34277c478bd9Sstevel@tonic-gate 	snap = ipmp_snap_create();
34287c478bd9Sstevel@tonic-gate 	if (snap == NULL)
34297c478bd9Sstevel@tonic-gate 		return (IPMP_ENOMEM);
34307c478bd9Sstevel@tonic-gate 
34317c478bd9Sstevel@tonic-gate 	/*
34327c478bd9Sstevel@tonic-gate 	 * Add group list.
34337c478bd9Sstevel@tonic-gate 	 */
34347c478bd9Sstevel@tonic-gate 	retval = getgrouplist(&snap->sn_grlistp);
3435e11c3f44Smeem 	if (retval != IPMP_SUCCESS)
3436e11c3f44Smeem 		goto failed;
34377c478bd9Sstevel@tonic-gate 
34387c478bd9Sstevel@tonic-gate 	/*
3439e11c3f44Smeem 	 * Add information for each group in the list, along with all of its
3440e11c3f44Smeem 	 * data addresses.
34417c478bd9Sstevel@tonic-gate 	 */
34427c478bd9Sstevel@tonic-gate 	grlistp = snap->sn_grlistp;
34437c478bd9Sstevel@tonic-gate 	for (i = 0; i < grlistp->gl_ngroup; i++) {
34447c478bd9Sstevel@tonic-gate 		retval = getgroupinfo(grlistp->gl_groups[i], &grinfop);
3445e11c3f44Smeem 		if (retval != IPMP_SUCCESS)
3446e11c3f44Smeem 			goto failed;
3447e11c3f44Smeem 
34487c478bd9Sstevel@tonic-gate 		retval = ipmp_snap_addgroupinfo(snap, grinfop);
34497c478bd9Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
34507c478bd9Sstevel@tonic-gate 			ipmp_freegroupinfo(grinfop);
3451e11c3f44Smeem 			goto failed;
3452e11c3f44Smeem 		}
3453e11c3f44Smeem 
3454e11c3f44Smeem 		adlistp = grinfop->gr_adlistp;
3455e11c3f44Smeem 		for (j = 0; j < adlistp->al_naddr; j++) {
3456e11c3f44Smeem 			retval = getgraddrinfo(grinfop->gr_name,
3457e11c3f44Smeem 			    &adlistp->al_addrs[j], &adinfop);
3458e11c3f44Smeem 			if (retval != IPMP_SUCCESS)
3459e11c3f44Smeem 				goto failed;
3460e11c3f44Smeem 
3461e11c3f44Smeem 			retval = ipmp_snap_addaddrinfo(snap, adinfop);
3462e11c3f44Smeem 			if (retval != IPMP_SUCCESS) {
3463e11c3f44Smeem 				ipmp_freeaddrinfo(adinfop);
3464e11c3f44Smeem 				goto failed;
3465e11c3f44Smeem 			}
34667c478bd9Sstevel@tonic-gate 		}
34677c478bd9Sstevel@tonic-gate 	}
34687c478bd9Sstevel@tonic-gate 
34697c478bd9Sstevel@tonic-gate 	/*
34707c478bd9Sstevel@tonic-gate 	 * Add information for each configured phyint.
34717c478bd9Sstevel@tonic-gate 	 */
34727c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
34737c478bd9Sstevel@tonic-gate 		retval = getifinfo(pi->pi_name, &ifinfop);
3474e11c3f44Smeem 		if (retval != IPMP_SUCCESS)
3475e11c3f44Smeem 			goto failed;
3476e11c3f44Smeem 
34777c478bd9Sstevel@tonic-gate 		retval = ipmp_snap_addifinfo(snap, ifinfop);
34787c478bd9Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
34797c478bd9Sstevel@tonic-gate 			ipmp_freeifinfo(ifinfop);
3480e11c3f44Smeem 			goto failed;
34817c478bd9Sstevel@tonic-gate 		}
34827c478bd9Sstevel@tonic-gate 	}
34837c478bd9Sstevel@tonic-gate 
34847c478bd9Sstevel@tonic-gate 	*snapp = snap;
34857c478bd9Sstevel@tonic-gate 	return (IPMP_SUCCESS);
3486e11c3f44Smeem failed:
3487e11c3f44Smeem 	ipmp_snap_free(snap);
3488e11c3f44Smeem 	return (retval);
34897c478bd9Sstevel@tonic-gate }
3490