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
5*921e7e07Smeem  * Common Development and Distribution License (the "License").
6*921e7e07Smeem  * 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 /*
22*921e7e07Smeem  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include "mpd_defs.h"
297c478bd9Sstevel@tonic-gate #include "mpd_tables.h"
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * Global list of phyints, phyint instances, phyint groups and the anonymous
337c478bd9Sstevel@tonic-gate  * group; the latter is initialized in phyint_init().
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate struct phyint *phyints = NULL;
367c478bd9Sstevel@tonic-gate struct phyint_instance	*phyint_instances = NULL;
377c478bd9Sstevel@tonic-gate struct phyint_group *phyint_groups = NULL;
387c478bd9Sstevel@tonic-gate struct phyint_group *phyint_anongroup;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * Grouplist signature; initialized in phyint_init().
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate static uint64_t phyint_grouplistsig;
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate static void phyint_inst_insert(struct phyint_instance *pii);
467c478bd9Sstevel@tonic-gate static void phyint_inst_print(struct phyint_instance *pii);
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static void phyint_insert(struct phyint *pi, struct phyint_group *pg);
497c478bd9Sstevel@tonic-gate static void phyint_delete(struct phyint *pi);
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static void phyint_group_insert(struct phyint_group *pg);
527c478bd9Sstevel@tonic-gate static void phyint_group_delete(struct phyint_group *pg);
537c478bd9Sstevel@tonic-gate static struct phyint_group *phyint_group_lookup(const char *pg_name);
547c478bd9Sstevel@tonic-gate static struct phyint_group *phyint_group_create(const char *pg_name);
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static void logint_print(struct logint *li);
577c478bd9Sstevel@tonic-gate static void logint_insert(struct phyint_instance *pii, struct logint *li);
587c478bd9Sstevel@tonic-gate static struct logint *logint_lookup(struct phyint_instance *pii, char *li_name);
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate static void target_print(struct target *tg);
617c478bd9Sstevel@tonic-gate static void target_insert(struct phyint_instance *pii, struct target *tg);
627c478bd9Sstevel@tonic-gate static struct target *target_first(struct phyint_instance *pii);
637c478bd9Sstevel@tonic-gate static struct target *target_select_best(struct phyint_instance *pii);
647c478bd9Sstevel@tonic-gate static void target_flush_hosts(struct phyint_group *pg);
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static void reset_pii_probes(struct phyint_instance *pii, struct target *tg);
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate static boolean_t phyint_inst_v6_sockinit(struct phyint_instance *pii);
697c478bd9Sstevel@tonic-gate static boolean_t phyint_inst_v4_sockinit(struct phyint_instance *pii);
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static void ip_index_to_mask_v6(uint_t masklen, struct in6_addr *bitmask);
727c478bd9Sstevel@tonic-gate static boolean_t prefix_equal(struct in6_addr p1, struct in6_addr p2,
737c478bd9Sstevel@tonic-gate     int prefix_len);
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static int phyint_state_event(struct phyint_group *pg, struct phyint *pi);
767c478bd9Sstevel@tonic-gate static int phyint_group_state_event(struct phyint_group *pg);
777c478bd9Sstevel@tonic-gate static int phyint_group_change_event(struct phyint_group *pg, ipmp_group_op_t);
787c478bd9Sstevel@tonic-gate static int phyint_group_member_event(struct phyint_group *pg, struct phyint *pi,
797c478bd9Sstevel@tonic-gate     ipmp_if_op_t op);
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static uint64_t gensig(void);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /* Initialize any per-file global state.  Returns 0 on success, -1 on failure */
847c478bd9Sstevel@tonic-gate int
857c478bd9Sstevel@tonic-gate phyint_init(void)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate 	phyint_grouplistsig = gensig();
887c478bd9Sstevel@tonic-gate 	if (track_all_phyints) {
897c478bd9Sstevel@tonic-gate 		phyint_anongroup = phyint_group_create("");
907c478bd9Sstevel@tonic-gate 		if (phyint_anongroup == NULL)
917c478bd9Sstevel@tonic-gate 			return (-1);
927c478bd9Sstevel@tonic-gate 		phyint_group_insert(phyint_anongroup);
937c478bd9Sstevel@tonic-gate 	}
947c478bd9Sstevel@tonic-gate 	return (0);
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /* Return the phyint with the given name */
987c478bd9Sstevel@tonic-gate struct phyint *
997c478bd9Sstevel@tonic-gate phyint_lookup(const char *name)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	struct phyint *pi;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
1047c478bd9Sstevel@tonic-gate 		logdebug("phyint_lookup(%s)\n", name);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
1077c478bd9Sstevel@tonic-gate 		if (strncmp(pi->pi_name, name, sizeof (pi->pi_name)) == 0)
1087c478bd9Sstevel@tonic-gate 			break;
1097c478bd9Sstevel@tonic-gate 	}
1107c478bd9Sstevel@tonic-gate 	return (pi);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /* Return the phyint instance with the given name and the given family */
1147c478bd9Sstevel@tonic-gate struct phyint_instance *
1157c478bd9Sstevel@tonic-gate phyint_inst_lookup(int af, char *name)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	struct phyint *pi;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
1207c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_lookup(%s %s)\n", AF_STR(af), name);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	assert(af == AF_INET || af == AF_INET6);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	pi = phyint_lookup(name);
1257c478bd9Sstevel@tonic-gate 	if (pi == NULL)
1267c478bd9Sstevel@tonic-gate 		return (NULL);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	return (PHYINT_INSTANCE(pi, af));
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate static struct phyint_group *
1327c478bd9Sstevel@tonic-gate phyint_group_lookup(const char *pg_name)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate 	struct phyint_group *pg;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
1377c478bd9Sstevel@tonic-gate 		logdebug("phyint_group_lookup(%s)\n", pg_name);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	for (pg = phyint_groups; pg != NULL; pg = pg->pg_next) {
1407c478bd9Sstevel@tonic-gate 		if (strncmp(pg->pg_name, pg_name, sizeof (pg->pg_name)) == 0)
1417c478bd9Sstevel@tonic-gate 			break;
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 	return (pg);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate /*
1477c478bd9Sstevel@tonic-gate  * Insert the phyint in the linked list of all phyints. If the phyint belongs
1487c478bd9Sstevel@tonic-gate  * to some group, insert it in the phyint group list.
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate static void
1517c478bd9Sstevel@tonic-gate phyint_insert(struct phyint *pi, struct phyint_group *pg)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
1547c478bd9Sstevel@tonic-gate 		logdebug("phyint_insert(%s '%s')\n", pi->pi_name, pg->pg_name);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	/* Insert the phyint at the head of the 'all phyints' list */
1577c478bd9Sstevel@tonic-gate 	pi->pi_next = phyints;
1587c478bd9Sstevel@tonic-gate 	pi->pi_prev = NULL;
1597c478bd9Sstevel@tonic-gate 	if (phyints != NULL)
1607c478bd9Sstevel@tonic-gate 		phyints->pi_prev = pi;
1617c478bd9Sstevel@tonic-gate 	phyints = pi;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/*
1647c478bd9Sstevel@tonic-gate 	 * Insert the phyint at the head of the 'phyint_group members' list
1657c478bd9Sstevel@tonic-gate 	 * of the phyint group to which it belongs.
1667c478bd9Sstevel@tonic-gate 	 */
1677c478bd9Sstevel@tonic-gate 	pi->pi_pgnext = NULL;
1687c478bd9Sstevel@tonic-gate 	pi->pi_pgprev = NULL;
1697c478bd9Sstevel@tonic-gate 	pi->pi_group = pg;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	pi->pi_pgnext = pg->pg_phyint;
1727c478bd9Sstevel@tonic-gate 	if (pi->pi_pgnext != NULL)
1737c478bd9Sstevel@tonic-gate 		pi->pi_pgnext->pi_pgprev = pi;
1747c478bd9Sstevel@tonic-gate 	pg->pg_phyint = pi;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	pg->pg_sig++;
1777c478bd9Sstevel@tonic-gate 	(void) phyint_group_member_event(pg, pi, IPMP_IF_ADD);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate /* Insert the phyint instance in the linked list of all phyint instances. */
1817c478bd9Sstevel@tonic-gate static void
1827c478bd9Sstevel@tonic-gate phyint_inst_insert(struct phyint_instance *pii)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
1857c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_insert(%s %s)\n",
1867c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name);
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	/*
1907c478bd9Sstevel@tonic-gate 	 * Insert the phyint at the head of the 'all phyint instances' list.
1917c478bd9Sstevel@tonic-gate 	 */
1927c478bd9Sstevel@tonic-gate 	pii->pii_next = phyint_instances;
1937c478bd9Sstevel@tonic-gate 	pii->pii_prev = NULL;
1947c478bd9Sstevel@tonic-gate 	if (phyint_instances != NULL)
1957c478bd9Sstevel@tonic-gate 		phyint_instances->pii_prev = pii;
1967c478bd9Sstevel@tonic-gate 	phyint_instances = pii;
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate /*
2007c478bd9Sstevel@tonic-gate  * Create a new phyint with the given parameters. Also insert it into
2017c478bd9Sstevel@tonic-gate  * the list of all phyints and the list of phyint group members by calling
2027c478bd9Sstevel@tonic-gate  * phyint_insert().
2037c478bd9Sstevel@tonic-gate  */
2047c478bd9Sstevel@tonic-gate static struct phyint *
2057c478bd9Sstevel@tonic-gate phyint_create(char *pi_name, struct phyint_group *pg, uint_t ifindex,
2067c478bd9Sstevel@tonic-gate     uint64_t flags)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	struct phyint *pi;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	pi = calloc(1, sizeof (struct phyint));
2117c478bd9Sstevel@tonic-gate 	if (pi == NULL) {
2127c478bd9Sstevel@tonic-gate 		logperror("phyint_create: calloc");
2137c478bd9Sstevel@tonic-gate 		return (NULL);
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	/*
2177c478bd9Sstevel@tonic-gate 	 * Record the phyint values. Also insert the phyint into the
2187c478bd9Sstevel@tonic-gate 	 * phyint group by calling phyint_insert().
2197c478bd9Sstevel@tonic-gate 	 */
2207c478bd9Sstevel@tonic-gate 	(void) strncpy(pi->pi_name, pi_name, sizeof (pi->pi_name));
2217c478bd9Sstevel@tonic-gate 	pi->pi_name[sizeof (pi->pi_name) - 1] = '\0';
2227c478bd9Sstevel@tonic-gate 	pi->pi_ifindex = ifindex;
2237c478bd9Sstevel@tonic-gate 	pi->pi_icmpid =
2247c478bd9Sstevel@tonic-gate 	    htons(((getpid() & 0xFF) << 8) | (pi->pi_ifindex & 0xFF));
2257c478bd9Sstevel@tonic-gate 	/*
2267c478bd9Sstevel@tonic-gate 	 * We optimistically start in the PI_RUNNING state.  Later (in
2277c478bd9Sstevel@tonic-gate 	 * process_link_state_changes()), we will readjust this to match the
2287c478bd9Sstevel@tonic-gate 	 * current state of the link.  Further, if test addresses are
2297c478bd9Sstevel@tonic-gate 	 * subsequently assigned, we will transition to PI_NOTARGETS and then
2307c478bd9Sstevel@tonic-gate 	 * either PI_RUNNING or PI_FAILED, depending on the result of the test
2317c478bd9Sstevel@tonic-gate 	 * probes.
2327c478bd9Sstevel@tonic-gate 	 */
2337c478bd9Sstevel@tonic-gate 	pi->pi_state = PI_RUNNING;
2347c478bd9Sstevel@tonic-gate 	pi->pi_flags = PHYINT_FLAGS(flags);
2357c478bd9Sstevel@tonic-gate 	/*
2367c478bd9Sstevel@tonic-gate 	 * Initialise the link state.  The link state is initialised to
2377c478bd9Sstevel@tonic-gate 	 * up, so that if the link is down when IPMP starts monitoring
2387c478bd9Sstevel@tonic-gate 	 * the interface, it will appear as though there has been a
2397c478bd9Sstevel@tonic-gate 	 * transition from the link up to link down.  This avoids
2407c478bd9Sstevel@tonic-gate 	 * having to treat this situation as a special case.
2417c478bd9Sstevel@tonic-gate 	 */
2427c478bd9Sstevel@tonic-gate 	INIT_LINK_STATE(pi);
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	/*
2457c478bd9Sstevel@tonic-gate 	 * Insert the phyint in the list of all phyints, and the
2467c478bd9Sstevel@tonic-gate 	 * list of phyint group members
2477c478bd9Sstevel@tonic-gate 	 */
2487c478bd9Sstevel@tonic-gate 	phyint_insert(pi, pg);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	/*
2517c478bd9Sstevel@tonic-gate 	 * If we are joining a failed group, mark the interface as
2527c478bd9Sstevel@tonic-gate 	 * failed.
2537c478bd9Sstevel@tonic-gate 	 */
2547c478bd9Sstevel@tonic-gate 	if (GROUP_FAILED(pg))
2557c478bd9Sstevel@tonic-gate 		(void) change_lif_flags(pi, IFF_FAILED, _B_TRUE);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	return (pi);
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate /*
2617c478bd9Sstevel@tonic-gate  * Create a new phyint instance belonging to the phyint 'pi' and address
2627c478bd9Sstevel@tonic-gate  * family 'af'. Also insert it into the list of all phyint instances by
2637c478bd9Sstevel@tonic-gate  * calling phyint_inst_insert().
2647c478bd9Sstevel@tonic-gate  */
2657c478bd9Sstevel@tonic-gate static struct phyint_instance *
2667c478bd9Sstevel@tonic-gate phyint_inst_create(struct phyint *pi, int af)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	pii = calloc(1, sizeof (struct phyint_instance));
2717c478bd9Sstevel@tonic-gate 	if (pii == NULL) {
2727c478bd9Sstevel@tonic-gate 		logperror("phyint_inst_create: calloc");
2737c478bd9Sstevel@tonic-gate 		return (NULL);
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	/*
2777c478bd9Sstevel@tonic-gate 	 * Attach the phyint instance to the phyint.
2787c478bd9Sstevel@tonic-gate 	 * Set the back pointers as well
2797c478bd9Sstevel@tonic-gate 	 */
2807c478bd9Sstevel@tonic-gate 	pii->pii_phyint = pi;
2817c478bd9Sstevel@tonic-gate 	if (af == AF_INET)
2827c478bd9Sstevel@tonic-gate 		pi->pi_v4 = pii;
2837c478bd9Sstevel@tonic-gate 	else
2847c478bd9Sstevel@tonic-gate 		pi->pi_v6 = pii;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	pii->pii_in_use = 1;
2877c478bd9Sstevel@tonic-gate 	pii->pii_probe_sock = -1;
2887c478bd9Sstevel@tonic-gate 	pii->pii_snxt = 1;
2897c478bd9Sstevel@tonic-gate 	pii->pii_af = af;
2907c478bd9Sstevel@tonic-gate 	pii->pii_fd_hrtime = gethrtime() +
2917c478bd9Sstevel@tonic-gate 	    (FAILURE_DETECTION_QP * (hrtime_t)NANOSEC);
2927c478bd9Sstevel@tonic-gate 	pii->pii_flags = pi->pi_flags;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/* Insert the phyint instance in the list of all phyint instances. */
2957c478bd9Sstevel@tonic-gate 	phyint_inst_insert(pii);
2967c478bd9Sstevel@tonic-gate 	return (pii);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate  * Change the state of phyint `pi' to state `state'.
3017c478bd9Sstevel@tonic-gate  */
3027c478bd9Sstevel@tonic-gate void
3037c478bd9Sstevel@tonic-gate phyint_chstate(struct phyint *pi, enum pi_state state)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	/*
3067c478bd9Sstevel@tonic-gate 	 * To simplify things, some callers always set a given state
3077c478bd9Sstevel@tonic-gate 	 * regardless of the previous state of the phyint (e.g., setting
3087c478bd9Sstevel@tonic-gate 	 * PI_RUNNING when it's already set).  We shouldn't bother
3097c478bd9Sstevel@tonic-gate 	 * generating an event or consuming a signature for these, since
3107c478bd9Sstevel@tonic-gate 	 * the actual state of the interface is unchanged.
3117c478bd9Sstevel@tonic-gate 	 */
3127c478bd9Sstevel@tonic-gate 	if (pi->pi_state == state)
3137c478bd9Sstevel@tonic-gate 		return;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	pi->pi_state = state;
3167c478bd9Sstevel@tonic-gate 	pi->pi_group->pg_sig++;
3177c478bd9Sstevel@tonic-gate 	(void) phyint_state_event(pi->pi_group, pi);
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate /*
3217c478bd9Sstevel@tonic-gate  * Note that the type of phyint `pi' has changed.
3227c478bd9Sstevel@tonic-gate  */
3237c478bd9Sstevel@tonic-gate void
3247c478bd9Sstevel@tonic-gate phyint_newtype(struct phyint *pi)
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	pi->pi_group->pg_sig++;
3277c478bd9Sstevel@tonic-gate 	(void) phyint_state_event(pi->pi_group, pi);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate  * Insert the phyint group in the linked list of all phyint groups
3327c478bd9Sstevel@tonic-gate  * at the head of the list
3337c478bd9Sstevel@tonic-gate  */
3347c478bd9Sstevel@tonic-gate static void
3357c478bd9Sstevel@tonic-gate phyint_group_insert(struct phyint_group *pg)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate 	pg->pg_next = phyint_groups;
3387c478bd9Sstevel@tonic-gate 	pg->pg_prev = NULL;
3397c478bd9Sstevel@tonic-gate 	if (phyint_groups != NULL)
3407c478bd9Sstevel@tonic-gate 		phyint_groups->pg_prev = pg;
3417c478bd9Sstevel@tonic-gate 	phyint_groups = pg;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	phyint_grouplistsig++;
3447c478bd9Sstevel@tonic-gate 	(void) phyint_group_change_event(pg, IPMP_GROUP_ADD);
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate /*
3487c478bd9Sstevel@tonic-gate  * Create a new phyint group called 'name'.
3497c478bd9Sstevel@tonic-gate  */
3507c478bd9Sstevel@tonic-gate static struct phyint_group *
3517c478bd9Sstevel@tonic-gate phyint_group_create(const char *name)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	struct	phyint_group *pg;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
3567c478bd9Sstevel@tonic-gate 		logdebug("phyint_group_create(%s)\n", name);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	pg = calloc(1, sizeof (struct phyint_group));
3597c478bd9Sstevel@tonic-gate 	if (pg == NULL) {
3607c478bd9Sstevel@tonic-gate 		logperror("phyint_group_create: calloc");
3617c478bd9Sstevel@tonic-gate 		return (NULL);
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	(void) strncpy(pg->pg_name, name, sizeof (pg->pg_name));
3657c478bd9Sstevel@tonic-gate 	pg->pg_name[sizeof (pg->pg_name) - 1] = '\0';
3667c478bd9Sstevel@tonic-gate 	pg->pg_sig = gensig();
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	pg->pg_fdt = user_failure_detection_time;
3697c478bd9Sstevel@tonic-gate 	pg->pg_probeint = user_probe_interval;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	return (pg);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate /*
3757c478bd9Sstevel@tonic-gate  * Change the state of the phyint group `pg' to state `state'.
3767c478bd9Sstevel@tonic-gate  */
3777c478bd9Sstevel@tonic-gate void
3787c478bd9Sstevel@tonic-gate phyint_group_chstate(struct phyint_group *pg, enum pg_state state)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	assert(pg != phyint_anongroup);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	switch (state) {
3837c478bd9Sstevel@tonic-gate 	case PG_FAILED:
3847c478bd9Sstevel@tonic-gate 		pg->pg_groupfailed = 1;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 		/*
3877c478bd9Sstevel@tonic-gate 		 * We can never know with certainty that a group has
3887c478bd9Sstevel@tonic-gate 		 * failed.  It is possible that all known targets have
3897c478bd9Sstevel@tonic-gate 		 * failed simultaneously, and new targets have come up
3907c478bd9Sstevel@tonic-gate 		 * instead. If the targets are routers then router
3917c478bd9Sstevel@tonic-gate 		 * discovery will kick in, and we will see the new routers
3927c478bd9Sstevel@tonic-gate 		 * thru routing socket messages. But if the targets are
3937c478bd9Sstevel@tonic-gate 		 * hosts, we have to discover it by multicast.	So flush
3947c478bd9Sstevel@tonic-gate 		 * all the host targets. The next probe will send out a
3957c478bd9Sstevel@tonic-gate 		 * multicast echo request. If this is a group failure, we
3967c478bd9Sstevel@tonic-gate 		 * will still not see any response, otherwise we will
3977c478bd9Sstevel@tonic-gate 		 * clear the pg_groupfailed flag after we get
3987c478bd9Sstevel@tonic-gate 		 * NUM_PROBE_REPAIRS consecutive unicast replies on any
3997c478bd9Sstevel@tonic-gate 		 * phyint.
4007c478bd9Sstevel@tonic-gate 		 */
4017c478bd9Sstevel@tonic-gate 		target_flush_hosts(pg);
4027c478bd9Sstevel@tonic-gate 		break;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	case PG_RUNNING:
4057c478bd9Sstevel@tonic-gate 		pg->pg_groupfailed = 0;
4067c478bd9Sstevel@tonic-gate 		break;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	default:
4097c478bd9Sstevel@tonic-gate 		logerr("phyint_group_chstate: invalid group state %d; "
4107c478bd9Sstevel@tonic-gate 		    "aborting\n", state);
4117c478bd9Sstevel@tonic-gate 		abort();
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	pg->pg_sig++;
4157c478bd9Sstevel@tonic-gate 	(void) phyint_group_state_event(pg);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate  * Create a new phyint instance and initialize it from the values supplied by
4207c478bd9Sstevel@tonic-gate  * the kernel. Always check for ENXIO before logging any error, because the
4217c478bd9Sstevel@tonic-gate  * interface could have vanished after completion of SIOCGLIFCONF.
4227c478bd9Sstevel@tonic-gate  * Return values:
4237c478bd9Sstevel@tonic-gate  *	pointer to the phyint instance on success
4247c478bd9Sstevel@tonic-gate  *	NULL on failure Eg. if the phyint instance is not found in the kernel
4257c478bd9Sstevel@tonic-gate  */
4267c478bd9Sstevel@tonic-gate struct phyint_instance *
4277c478bd9Sstevel@tonic-gate phyint_inst_init_from_k(int af, char *pi_name)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate 	char	pg_name[LIFNAMSIZ + 1];
4307c478bd9Sstevel@tonic-gate 	int	ifsock;
4317c478bd9Sstevel@tonic-gate 	uint_t	ifindex;
4327c478bd9Sstevel@tonic-gate 	uint64_t	flags;
4337c478bd9Sstevel@tonic-gate 	struct lifreq	lifr;
4347c478bd9Sstevel@tonic-gate 	struct phyint	*pi;
4357c478bd9Sstevel@tonic-gate 	struct phyint_instance	*pii;
4367c478bd9Sstevel@tonic-gate 	boolean_t	pg_created;
4377c478bd9Sstevel@tonic-gate 	boolean_t	pi_created;
4387c478bd9Sstevel@tonic-gate 	struct phyint_group	*pg;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate retry:
4417c478bd9Sstevel@tonic-gate 	pii = NULL;
4427c478bd9Sstevel@tonic-gate 	pi = NULL;
4437c478bd9Sstevel@tonic-gate 	pg = NULL;
4447c478bd9Sstevel@tonic-gate 	pi_created = _B_FALSE;
4457c478bd9Sstevel@tonic-gate 	pg_created = _B_FALSE;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
4487c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_init_from_k(%s %s)\n",
4497c478bd9Sstevel@tonic-gate 		    AF_STR(af), pi_name);
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	assert(af == AF_INET || af == AF_INET6);
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	/* Get the socket for doing ioctls */
4557c478bd9Sstevel@tonic-gate 	ifsock = (af == AF_INET) ? ifsock_v4 : ifsock_v6;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	/*
4587c478bd9Sstevel@tonic-gate 	 * Get the interface flags. Ignore loopback and multipoint
4597c478bd9Sstevel@tonic-gate 	 * interfaces.
4607c478bd9Sstevel@tonic-gate 	 */
4617c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi_name, sizeof (lifr.lifr_name));
4627c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
4637c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
4647c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
4657c478bd9Sstevel@tonic-gate 			logperror("phyint_inst_init_from_k:"
4667c478bd9Sstevel@tonic-gate 			    " ioctl (get flags)");
4677c478bd9Sstevel@tonic-gate 		}
4687c478bd9Sstevel@tonic-gate 		return (NULL);
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 	flags = lifr.lifr_flags;
4717c478bd9Sstevel@tonic-gate 	if (!(flags & IFF_MULTICAST) || (flags & IFF_LOOPBACK))
4727c478bd9Sstevel@tonic-gate 		return (NULL);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	/*
4757c478bd9Sstevel@tonic-gate 	 * Get the ifindex for recording later in our tables, in case we need
4767c478bd9Sstevel@tonic-gate 	 * to create a new phyint.
4777c478bd9Sstevel@tonic-gate 	 */
4787c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFINDEX, (char *)&lifr) < 0) {
4797c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
4807c478bd9Sstevel@tonic-gate 			logperror("phyint_inst_init_from_k: "
4817c478bd9Sstevel@tonic-gate 			    " ioctl (get lifindex)");
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate 		return (NULL);
4847c478bd9Sstevel@tonic-gate 	}
4857c478bd9Sstevel@tonic-gate 	ifindex = lifr.lifr_index;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/*
4887c478bd9Sstevel@tonic-gate 	 * Get the phyint group name of this phyint, from the kernel.
4897c478bd9Sstevel@tonic-gate 	 */
4907c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFGROUPNAME, (char *)&lifr) < 0) {
4917c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
4927c478bd9Sstevel@tonic-gate 			logperror("phyint_inst_init_from_k: "
4937c478bd9Sstevel@tonic-gate 			    "ioctl (get group name)");
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 		return (NULL);
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 	(void) strncpy(pg_name, lifr.lifr_groupname, sizeof (pg_name));
4987c478bd9Sstevel@tonic-gate 	pg_name[sizeof (pg_name) - 1] = '\0';
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	/*
5017c478bd9Sstevel@tonic-gate 	 * If the phyint is not part of any group, pg_name is the
5027c478bd9Sstevel@tonic-gate 	 * null string. If 'track_all_phyints' is false, there is no
5037c478bd9Sstevel@tonic-gate 	 * need to create a phyint.
5047c478bd9Sstevel@tonic-gate 	 */
5057c478bd9Sstevel@tonic-gate 	if (pg_name[0] == '\0' && !track_all_phyints) {
5067c478bd9Sstevel@tonic-gate 		/*
5077c478bd9Sstevel@tonic-gate 		 * If the IFF_FAILED or IFF_OFFLINE flags are set, reset
5087c478bd9Sstevel@tonic-gate 		 * them. These flags shouldn't be set if IPMP isn't
5097c478bd9Sstevel@tonic-gate 		 * tracking the interface.
5107c478bd9Sstevel@tonic-gate 		 */
5117c478bd9Sstevel@tonic-gate 		if ((flags & (IFF_FAILED | IFF_OFFLINE)) != 0) {
5127c478bd9Sstevel@tonic-gate 			lifr.lifr_flags = flags & ~(IFF_FAILED | IFF_OFFLINE);
5137c478bd9Sstevel@tonic-gate 			if (ioctl(ifsock, SIOCSLIFFLAGS, (char *)&lifr) < 0) {
5147c478bd9Sstevel@tonic-gate 				if (errno != ENXIO) {
5157c478bd9Sstevel@tonic-gate 					logperror("phyint_inst_init_from_k:"
5167c478bd9Sstevel@tonic-gate 					    " ioctl (set flags)");
5177c478bd9Sstevel@tonic-gate 				}
5187c478bd9Sstevel@tonic-gate 			}
5197c478bd9Sstevel@tonic-gate 		}
5207c478bd9Sstevel@tonic-gate 		return (NULL);
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	/*
5247c478bd9Sstevel@tonic-gate 	 * We need to create a new phyint instance. A phyint instance
5257c478bd9Sstevel@tonic-gate 	 * belongs to a phyint, and the phyint belongs to a phyint group.
5267c478bd9Sstevel@tonic-gate 	 * So we first lookup the 'parents' and if they don't exist then
5277c478bd9Sstevel@tonic-gate 	 * we create them.
5287c478bd9Sstevel@tonic-gate 	 */
5297c478bd9Sstevel@tonic-gate 	pg = phyint_group_lookup(pg_name);
5307c478bd9Sstevel@tonic-gate 	if (pg == NULL) {
5317c478bd9Sstevel@tonic-gate 		pg = phyint_group_create(pg_name);
5327c478bd9Sstevel@tonic-gate 		if (pg == NULL) {
5337c478bd9Sstevel@tonic-gate 			logerr("phyint_inst_init_from_k:"
5347c478bd9Sstevel@tonic-gate 			    " unable to create group %s\n", pg_name);
5357c478bd9Sstevel@tonic-gate 			return (NULL);
5367c478bd9Sstevel@tonic-gate 		}
5377c478bd9Sstevel@tonic-gate 		phyint_group_insert(pg);
5387c478bd9Sstevel@tonic-gate 		pg_created = _B_TRUE;
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	/*
5427c478bd9Sstevel@tonic-gate 	 * Lookup the phyint. If the phyint does not exist create it.
5437c478bd9Sstevel@tonic-gate 	 */
5447c478bd9Sstevel@tonic-gate 	pi = phyint_lookup(pi_name);
5457c478bd9Sstevel@tonic-gate 	if (pi == NULL) {
5467c478bd9Sstevel@tonic-gate 		pi = phyint_create(pi_name, pg, ifindex, flags);
5477c478bd9Sstevel@tonic-gate 		if (pi == NULL) {
5487c478bd9Sstevel@tonic-gate 			logerr("phyint_inst_init_from_k:"
5497c478bd9Sstevel@tonic-gate 			    " unable to create phyint %s\n", pi_name);
5507c478bd9Sstevel@tonic-gate 			if (pg_created)
5517c478bd9Sstevel@tonic-gate 				phyint_group_delete(pg);
5527c478bd9Sstevel@tonic-gate 			return (NULL);
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 		pi_created = _B_TRUE;
5557c478bd9Sstevel@tonic-gate 	} else {
5567c478bd9Sstevel@tonic-gate 		/* The phyint exists already. */
5577c478bd9Sstevel@tonic-gate 		assert(pi_created == _B_FALSE);
5587c478bd9Sstevel@tonic-gate 		/*
5597c478bd9Sstevel@tonic-gate 		 * Normally we should see consistent values for the IPv4 and
5607c478bd9Sstevel@tonic-gate 		 * IPv6 instances, for phyint properties. If we don't, it
5617c478bd9Sstevel@tonic-gate 		 * means things have changed underneath us, and we should
5627c478bd9Sstevel@tonic-gate 		 * resync our tables with the kernel. Check whether the
5637c478bd9Sstevel@tonic-gate 		 * interface index has changed. If so, it is most likely
5647c478bd9Sstevel@tonic-gate 		 * the interface has been unplumbed and replumbed,
5657c478bd9Sstevel@tonic-gate 		 * while we are yet to update our tables. Do it now.
5667c478bd9Sstevel@tonic-gate 		 */
5677c478bd9Sstevel@tonic-gate 		if (pi->pi_ifindex != ifindex) {
5687c478bd9Sstevel@tonic-gate 			if (pg_created)
5697c478bd9Sstevel@tonic-gate 				phyint_group_delete(pg);
5707c478bd9Sstevel@tonic-gate 			phyint_inst_delete(PHYINT_INSTANCE(pi, AF_OTHER(af)));
5717c478bd9Sstevel@tonic-gate 			goto retry;
5727c478bd9Sstevel@tonic-gate 		}
5737c478bd9Sstevel@tonic-gate 		assert(PHYINT_INSTANCE(pi, af) == NULL);
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		/*
5767c478bd9Sstevel@tonic-gate 		 * If the group name seen by the IPv4 and IPv6 instances
5777c478bd9Sstevel@tonic-gate 		 * are different, it is most likely the groupname has
5787c478bd9Sstevel@tonic-gate 		 * changed, while we are yet to update our tables. Do it now.
5797c478bd9Sstevel@tonic-gate 		 */
5807c478bd9Sstevel@tonic-gate 		if (strcmp(pi->pi_group->pg_name, pg_name) != 0) {
5817c478bd9Sstevel@tonic-gate 			if (pg_created)
5827c478bd9Sstevel@tonic-gate 				phyint_group_delete(pg);
5837c478bd9Sstevel@tonic-gate 			restore_phyint(pi);
5847c478bd9Sstevel@tonic-gate 			phyint_inst_delete(PHYINT_INSTANCE(pi,
5857c478bd9Sstevel@tonic-gate 			    AF_OTHER(af)));
5867c478bd9Sstevel@tonic-gate 			goto retry;
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	/*
5917c478bd9Sstevel@tonic-gate 	 * Create a new phyint instance, corresponding to the 'af'
5927c478bd9Sstevel@tonic-gate 	 * passed in.
5937c478bd9Sstevel@tonic-gate 	 */
5947c478bd9Sstevel@tonic-gate 	pii = phyint_inst_create(pi, af);
5957c478bd9Sstevel@tonic-gate 	if (pii == NULL) {
5967c478bd9Sstevel@tonic-gate 		logerr("phyint_inst_init_from_k: unable to create"
5977c478bd9Sstevel@tonic-gate 		    "phyint inst %s\n", pi->pi_name);
5987c478bd9Sstevel@tonic-gate 		if (pi_created) {
5997c478bd9Sstevel@tonic-gate 			/*
6007c478bd9Sstevel@tonic-gate 			 * Deleting the phyint will delete the phyint group
6017c478bd9Sstevel@tonic-gate 			 * if this is the last phyint in the group.
6027c478bd9Sstevel@tonic-gate 			 */
6037c478bd9Sstevel@tonic-gate 			phyint_delete(pi);
6047c478bd9Sstevel@tonic-gate 		}
6057c478bd9Sstevel@tonic-gate 		return (NULL);
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	return (pii);
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate /*
612*921e7e07Smeem  * Bind pii_probe_sock to the address associated with pii_probe_logint.
613*921e7e07Smeem  * This socket will be used for sending and receiving ICMP/ICMPv6 probes to
614*921e7e07Smeem  * targets. Do the common part in this function, and complete the
615*921e7e07Smeem  * initializations by calling the protocol specific functions
6167c478bd9Sstevel@tonic-gate  * phyint_inst_v{4,6}_sockinit() respectively.
6177c478bd9Sstevel@tonic-gate  *
6187c478bd9Sstevel@tonic-gate  * Return values: _B_TRUE/_B_FALSE for success or failure respectively.
6197c478bd9Sstevel@tonic-gate  */
6207c478bd9Sstevel@tonic-gate boolean_t
6217c478bd9Sstevel@tonic-gate phyint_inst_sockinit(struct phyint_instance *pii)
6227c478bd9Sstevel@tonic-gate {
6237c478bd9Sstevel@tonic-gate 	boolean_t success;
6247c478bd9Sstevel@tonic-gate 	struct phyint_group *pg;
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
6277c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_sockinit(%s %s)\n",
6287c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name);
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	assert(pii->pii_probe_logint != NULL);
6327c478bd9Sstevel@tonic-gate 	assert(pii->pii_probe_logint->li_flags & IFF_UP);
633*921e7e07Smeem 	assert(pii->pii_probe_logint->li_flags & IFF_NOFAILOVER);
6347c478bd9Sstevel@tonic-gate 	assert(pii->pii_af == AF_INET || pii->pii_af == AF_INET6);
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/*
6377c478bd9Sstevel@tonic-gate 	 * If the socket is already bound, close pii_probe_sock
6387c478bd9Sstevel@tonic-gate 	 */
6397c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock != -1)
6407c478bd9Sstevel@tonic-gate 		close_probe_socket(pii, _B_TRUE);
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	/*
6437c478bd9Sstevel@tonic-gate 	 * If the phyint is not part of a named group and track_all_phyints is
6447c478bd9Sstevel@tonic-gate 	 * false, simply return.
6457c478bd9Sstevel@tonic-gate 	 */
6467c478bd9Sstevel@tonic-gate 	pg = pii->pii_phyint->pi_group;
6477c478bd9Sstevel@tonic-gate 	if (pg == phyint_anongroup && !track_all_phyints) {
6487c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT)
6497c478bd9Sstevel@tonic-gate 			logdebug("phyint_inst_sockinit: no group\n");
6507c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
6517c478bd9Sstevel@tonic-gate 	}
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	/*
6547c478bd9Sstevel@tonic-gate 	 * Initialize the socket by calling the protocol specific function.
6557c478bd9Sstevel@tonic-gate 	 * If it succeeds, add the socket to the poll list.
6567c478bd9Sstevel@tonic-gate 	 */
6577c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET6)
6587c478bd9Sstevel@tonic-gate 		success = phyint_inst_v6_sockinit(pii);
6597c478bd9Sstevel@tonic-gate 	else
6607c478bd9Sstevel@tonic-gate 		success = phyint_inst_v4_sockinit(pii);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	if (success && (poll_add(pii->pii_probe_sock) == 0))
6637c478bd9Sstevel@tonic-gate 		return (_B_TRUE);
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	/* Something failed, cleanup and return false */
6667c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock != -1)
6677c478bd9Sstevel@tonic-gate 		close_probe_socket(pii, _B_FALSE);
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	return (_B_FALSE);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate /*
6737c478bd9Sstevel@tonic-gate  * IPv6 specific part in initializing the pii_probe_sock. This socket is
6747c478bd9Sstevel@tonic-gate  * used to send/receive ICMPv6 probe packets.
6757c478bd9Sstevel@tonic-gate  */
6767c478bd9Sstevel@tonic-gate static boolean_t
6777c478bd9Sstevel@tonic-gate phyint_inst_v6_sockinit(struct phyint_instance *pii)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	icmp6_filter_t filter;
6807c478bd9Sstevel@tonic-gate 	int hopcount = 1;
6817c478bd9Sstevel@tonic-gate 	int int_op;
6827c478bd9Sstevel@tonic-gate 	struct	sockaddr_in6	testaddr;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	/*
6857c478bd9Sstevel@tonic-gate 	 * Open a raw socket with ICMPv6 protocol.
6867c478bd9Sstevel@tonic-gate 	 *
6877c478bd9Sstevel@tonic-gate 	 * Use IPV6_DONTFAILOVER_IF to make sure that probes go out
6887c478bd9Sstevel@tonic-gate 	 * on the specified phyint only, and are not subject to load
6897c478bd9Sstevel@tonic-gate 	 * balancing. Bind to the src address chosen will ensure that
6907c478bd9Sstevel@tonic-gate 	 * the responses are received only on the specified phyint.
6917c478bd9Sstevel@tonic-gate 	 *
6927c478bd9Sstevel@tonic-gate 	 * Set the hopcount to 1 so that probe packets are not routed.
6937c478bd9Sstevel@tonic-gate 	 * Disable multicast loopback. Set the receive filter to
6947c478bd9Sstevel@tonic-gate 	 * receive only ICMPv6 echo replies.
6957c478bd9Sstevel@tonic-gate 	 */
6967c478bd9Sstevel@tonic-gate 	pii->pii_probe_sock = socket(pii->pii_af, SOCK_RAW, IPPROTO_ICMPV6);
6977c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock < 0) {
6987c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: socket");
6997c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	bzero(&testaddr, sizeof (testaddr));
7037c478bd9Sstevel@tonic-gate 	testaddr.sin6_family = AF_INET6;
7047c478bd9Sstevel@tonic-gate 	testaddr.sin6_port = 0;
7057c478bd9Sstevel@tonic-gate 	testaddr.sin6_addr = pii->pii_probe_logint->li_addr;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	if (bind(pii->pii_probe_sock, (struct sockaddr *)&testaddr,
7087c478bd9Sstevel@tonic-gate 	    sizeof (testaddr)) < 0) {
7097c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: IPv6 bind");
7107c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	/*
7147c478bd9Sstevel@tonic-gate 	 * IPV6_DONTFAILOVER_IF option takes precedence over setting
7157c478bd9Sstevel@tonic-gate 	 * IP_MULTICAST_IF. So we don't set IPV6_MULTICAST_IF again.
7167c478bd9Sstevel@tonic-gate 	 */
7177c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_DONTFAILOVER_IF,
7187c478bd9Sstevel@tonic-gate 	    (char *)&pii->pii_ifindex, sizeof (uint_t)) < 0) {
7197c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
7207c478bd9Sstevel@tonic-gate 		    " IPV6_DONTFAILOVER_IF");
7217c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
7227c478bd9Sstevel@tonic-gate 	}
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
7257c478bd9Sstevel@tonic-gate 	    (char *)&hopcount, sizeof (hopcount)) < 0) {
7267c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
7277c478bd9Sstevel@tonic-gate 		    " IPV6_UNICAST_HOPS");
7287c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
7297c478bd9Sstevel@tonic-gate 	}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
7327c478bd9Sstevel@tonic-gate 	    (char *)&hopcount, sizeof (hopcount)) < 0) {
7337c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
7347c478bd9Sstevel@tonic-gate 		    " IPV6_MULTICAST_HOPS");
7357c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
7367c478bd9Sstevel@tonic-gate 	}
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	int_op = 0;	/* used to turn off option */
7397c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
7407c478bd9Sstevel@tonic-gate 	    (char *)&int_op, sizeof (int_op)) < 0) {
7417c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
7427c478bd9Sstevel@tonic-gate 		    " IPV6_MULTICAST_LOOP");
7437c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
7447c478bd9Sstevel@tonic-gate 	}
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	/*
7477c478bd9Sstevel@tonic-gate 	 * Filter out so that we only receive ICMP echo replies
7487c478bd9Sstevel@tonic-gate 	 */
7497c478bd9Sstevel@tonic-gate 	ICMP6_FILTER_SETBLOCKALL(&filter);
7507c478bd9Sstevel@tonic-gate 	ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_ICMPV6, ICMP6_FILTER,
7537c478bd9Sstevel@tonic-gate 	    (char *)&filter, sizeof (filter)) < 0) {
7547c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
7557c478bd9Sstevel@tonic-gate 		    " ICMP6_FILTER");
7567c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	/* Enable receipt of ancillary data */
7607c478bd9Sstevel@tonic-gate 	int_op = 1;
7617c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
7627c478bd9Sstevel@tonic-gate 	    (char *)&int_op, sizeof (int_op)) < 0) {
7637c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
7647c478bd9Sstevel@tonic-gate 		    " IPV6_RECVHOPLIMIT");
7657c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
7697c478bd9Sstevel@tonic-gate }
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate /*
7727c478bd9Sstevel@tonic-gate  * IPv4 specific part in initializing the pii_probe_sock. This socket is
7737c478bd9Sstevel@tonic-gate  * used to send/receive ICMPv4 probe packets.
7747c478bd9Sstevel@tonic-gate  */
7757c478bd9Sstevel@tonic-gate static boolean_t
7767c478bd9Sstevel@tonic-gate phyint_inst_v4_sockinit(struct phyint_instance *pii)
7777c478bd9Sstevel@tonic-gate {
7787c478bd9Sstevel@tonic-gate 	struct sockaddr_in  testaddr;
7797c478bd9Sstevel@tonic-gate 	char	char_op;
7807c478bd9Sstevel@tonic-gate 	int	ttl = 1;
7817c478bd9Sstevel@tonic-gate 	char	char_ttl = 1;
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	/*
7847c478bd9Sstevel@tonic-gate 	 * Open a raw socket with ICMPv4 protocol.
7857c478bd9Sstevel@tonic-gate 	 *
7867c478bd9Sstevel@tonic-gate 	 * Use IP_DONTFAILOVER_IF to make sure that probes go out
7877c478bd9Sstevel@tonic-gate 	 * on the specified phyint only, and are not subject to load
7887c478bd9Sstevel@tonic-gate 	 * balancing. Bind to the src address chosen will ensure that
7897c478bd9Sstevel@tonic-gate 	 * the responses are received only on the specified phyint.
7907c478bd9Sstevel@tonic-gate 	 *
7917c478bd9Sstevel@tonic-gate 	 * Set the ttl to 1 so that probe packets are not routed.
7927c478bd9Sstevel@tonic-gate 	 * Disable multicast loopback.
7937c478bd9Sstevel@tonic-gate 	 */
7947c478bd9Sstevel@tonic-gate 	pii->pii_probe_sock = socket(pii->pii_af, SOCK_RAW, IPPROTO_ICMP);
7957c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock < 0) {
7967c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: socket");
7977c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	bzero(&testaddr, sizeof (testaddr));
8017c478bd9Sstevel@tonic-gate 	testaddr.sin_family = AF_INET;
8027c478bd9Sstevel@tonic-gate 	testaddr.sin_port = 0;
8037c478bd9Sstevel@tonic-gate 	IN6_V4MAPPED_TO_INADDR(&pii->pii_probe_logint->li_addr,
8047c478bd9Sstevel@tonic-gate 	    &testaddr.sin_addr);
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	if (bind(pii->pii_probe_sock, (struct sockaddr *)&testaddr,
8077c478bd9Sstevel@tonic-gate 	    sizeof (testaddr)) < 0) {
8087c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: IPv4 bind");
8097c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
8107c478bd9Sstevel@tonic-gate 	}
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	/*
8137c478bd9Sstevel@tonic-gate 	 * IP_DONTFAILOVER_IF option takes precedence over setting
8147c478bd9Sstevel@tonic-gate 	 * IP_MULTICAST_IF. So we don't set IP_MULTICAST_IF again.
8157c478bd9Sstevel@tonic-gate 	 */
8167c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_DONTFAILOVER_IF,
8177c478bd9Sstevel@tonic-gate 	    (char *)&testaddr.sin_addr, sizeof (struct in_addr)) < 0) {
8187c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
8197c478bd9Sstevel@tonic-gate 		    " IP_DONTFAILOVER");
8207c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_TTL,
8247c478bd9Sstevel@tonic-gate 	    (char *)&ttl, sizeof (ttl)) < 0) {
8257c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
8267c478bd9Sstevel@tonic-gate 		    " IP_TTL");
8277c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	char_op = 0;	/* used to turn off option */
8317c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
8327c478bd9Sstevel@tonic-gate 	    (char *)&char_op, sizeof (char_op)) == -1) {
8337c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
8347c478bd9Sstevel@tonic-gate 		    " IP_MULTICAST_LOOP");
8357c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_MULTICAST_TTL,
8397c478bd9Sstevel@tonic-gate 	    (char *)&char_ttl, sizeof (char_ttl)) == -1) {
8407c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
8417c478bd9Sstevel@tonic-gate 		    " IP_MULTICAST_TTL");
8427c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
8437c478bd9Sstevel@tonic-gate 	}
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate /*
8497c478bd9Sstevel@tonic-gate  * Remove the phyint group from the list of 'all phyint groups'
8507c478bd9Sstevel@tonic-gate  * and free it.
8517c478bd9Sstevel@tonic-gate  */
8527c478bd9Sstevel@tonic-gate static void
8537c478bd9Sstevel@tonic-gate phyint_group_delete(struct phyint_group *pg)
8547c478bd9Sstevel@tonic-gate {
8557c478bd9Sstevel@tonic-gate 	/*
8567c478bd9Sstevel@tonic-gate 	 * The anonymous group always exists, even when empty.
8577c478bd9Sstevel@tonic-gate 	 */
8587c478bd9Sstevel@tonic-gate 	if (pg == phyint_anongroup)
8597c478bd9Sstevel@tonic-gate 		return;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
8627c478bd9Sstevel@tonic-gate 		logdebug("phyint_group_delete('%s')\n", pg->pg_name);
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	/*
8657c478bd9Sstevel@tonic-gate 	 * The phyint group must be empty, and must not have any phyints.
8667c478bd9Sstevel@tonic-gate 	 * The phyint group must be in the list of all phyint groups
8677c478bd9Sstevel@tonic-gate 	 */
8687c478bd9Sstevel@tonic-gate 	assert(pg->pg_phyint == NULL);
8697c478bd9Sstevel@tonic-gate 	assert(phyint_groups == pg || pg->pg_prev != NULL);
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	if (pg->pg_prev != NULL)
8727c478bd9Sstevel@tonic-gate 		pg->pg_prev->pg_next = pg->pg_next;
8737c478bd9Sstevel@tonic-gate 	else
8747c478bd9Sstevel@tonic-gate 		phyint_groups = pg->pg_next;
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	if (pg->pg_next != NULL)
8777c478bd9Sstevel@tonic-gate 		pg->pg_next->pg_prev = pg->pg_prev;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	pg->pg_next = NULL;
8807c478bd9Sstevel@tonic-gate 	pg->pg_prev = NULL;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	phyint_grouplistsig++;
8837c478bd9Sstevel@tonic-gate 	(void) phyint_group_change_event(pg, IPMP_GROUP_REMOVE);
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	free(pg);
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate /*
8897c478bd9Sstevel@tonic-gate  * Extract information from the kernel about the desired phyint.
8907c478bd9Sstevel@tonic-gate  * Look only for properties of the phyint and not properties of logints.
8917c478bd9Sstevel@tonic-gate  * Take appropriate action on the changes.
8927c478bd9Sstevel@tonic-gate  * Return codes:
8937c478bd9Sstevel@tonic-gate  *	PI_OK
8947c478bd9Sstevel@tonic-gate  *		The phyint exists in the kernel and matches our knowledge
8957c478bd9Sstevel@tonic-gate  *		of the phyint.
8967c478bd9Sstevel@tonic-gate  *	PI_DELETED
8977c478bd9Sstevel@tonic-gate  *		The phyint has vanished in the kernel.
8987c478bd9Sstevel@tonic-gate  *	PI_IFINDEX_CHANGED
8997c478bd9Sstevel@tonic-gate  *		The phyint's interface index has changed.
9007c478bd9Sstevel@tonic-gate  *		Ask the caller to delete and recreate the phyint.
9017c478bd9Sstevel@tonic-gate  *	PI_IOCTL_ERROR
9027c478bd9Sstevel@tonic-gate  *		Some ioctl error. Don't change anything.
9037c478bd9Sstevel@tonic-gate  *	PI_GROUP_CHANGED
9047c478bd9Sstevel@tonic-gate  *		The phyint has changed group.
9057c478bd9Sstevel@tonic-gate  */
9067c478bd9Sstevel@tonic-gate int
9077c478bd9Sstevel@tonic-gate phyint_inst_update_from_k(struct phyint_instance *pii)
9087c478bd9Sstevel@tonic-gate {
9097c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
9107c478bd9Sstevel@tonic-gate 	int	ifsock;
9117c478bd9Sstevel@tonic-gate 	struct phyint *pi;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	pi = pii->pii_phyint;
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
9167c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_update_from_k(%s %s)\n",
9177c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pi->pi_name);
9187c478bd9Sstevel@tonic-gate 	}
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	/*
9217c478bd9Sstevel@tonic-gate 	 * Get the ifindex from the kernel, for comparison with the
9227c478bd9Sstevel@tonic-gate 	 * value in our tables.
9237c478bd9Sstevel@tonic-gate 	 */
9247c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
9257c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	ifsock = (pii->pii_af == AF_INET) ? ifsock_v4 : ifsock_v6;
9287c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFINDEX, &lifr) < 0) {
9297c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
9307c478bd9Sstevel@tonic-gate 			return (PI_DELETED);
9317c478bd9Sstevel@tonic-gate 		} else {
9327c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "phyint_inst_update_from_k:"
9337c478bd9Sstevel@tonic-gate 			    " ioctl (get lifindex)");
9347c478bd9Sstevel@tonic-gate 			return (PI_IOCTL_ERROR);
9357c478bd9Sstevel@tonic-gate 		}
9367c478bd9Sstevel@tonic-gate 	}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	if (lifr.lifr_index != pi->pi_ifindex) {
9397c478bd9Sstevel@tonic-gate 		/*
9407c478bd9Sstevel@tonic-gate 		 * The index has changed. Most likely the interface has
9417c478bd9Sstevel@tonic-gate 		 * been unplumbed and replumbed. Ask the caller to take
9427c478bd9Sstevel@tonic-gate 		 * appropriate action.
9437c478bd9Sstevel@tonic-gate 		 */
9447c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT) {
9457c478bd9Sstevel@tonic-gate 			logdebug("phyint_inst_update_from_k:"
9467c478bd9Sstevel@tonic-gate 			    " old index %d new index %d\n",
9477c478bd9Sstevel@tonic-gate 			    pi->pi_ifindex, lifr.lifr_index);
9487c478bd9Sstevel@tonic-gate 		}
9497c478bd9Sstevel@tonic-gate 		return (PI_IFINDEX_CHANGED);
9507c478bd9Sstevel@tonic-gate 	}
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	/*
9537c478bd9Sstevel@tonic-gate 	 * Get the group name from the kernel, for comparison with
9547c478bd9Sstevel@tonic-gate 	 * the value in our tables.
9557c478bd9Sstevel@tonic-gate 	 */
9567c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFGROUPNAME, &lifr) < 0) {
9577c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
9587c478bd9Sstevel@tonic-gate 			return (PI_DELETED);
9597c478bd9Sstevel@tonic-gate 		} else {
9607c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "phyint_inst_update_from_k:"
9617c478bd9Sstevel@tonic-gate 			    " ioctl (get groupname)");
9627c478bd9Sstevel@tonic-gate 			return (PI_IOCTL_ERROR);
9637c478bd9Sstevel@tonic-gate 		}
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	/*
9677c478bd9Sstevel@tonic-gate 	 * If the phyint has changed group i.e. if the phyint group name
9687c478bd9Sstevel@tonic-gate 	 * returned by the kernel is different, ask the caller to delete
9697c478bd9Sstevel@tonic-gate 	 * and recreate the phyint in the right group
9707c478bd9Sstevel@tonic-gate 	 */
9717c478bd9Sstevel@tonic-gate 	if (strcmp(lifr.lifr_groupname, pi->pi_group->pg_name) != 0) {
9727c478bd9Sstevel@tonic-gate 		/* Groupname has changed */
9737c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT) {
9747c478bd9Sstevel@tonic-gate 			logdebug("phyint_inst_update_from_k:"
9757c478bd9Sstevel@tonic-gate 			    " groupname change\n");
9767c478bd9Sstevel@tonic-gate 		}
9777c478bd9Sstevel@tonic-gate 		return (PI_GROUP_CHANGED);
9787c478bd9Sstevel@tonic-gate 	}
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	/*
9817c478bd9Sstevel@tonic-gate 	 * Get the current phyint flags from the kernel, and determine what
9827c478bd9Sstevel@tonic-gate 	 * flags have changed by comparing against our tables.	Note that the
9837c478bd9Sstevel@tonic-gate 	 * IFF_INACTIVE processing in initifs() relies on this call to ensure
9847c478bd9Sstevel@tonic-gate 	 * that IFF_INACTIVE is really still set on the interface.
9857c478bd9Sstevel@tonic-gate 	 */
9867c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFFLAGS, &lifr) < 0) {
9877c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
9887c478bd9Sstevel@tonic-gate 			return (PI_DELETED);
9897c478bd9Sstevel@tonic-gate 		} else {
9907c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "phyint_inst_update_from_k: "
9917c478bd9Sstevel@tonic-gate 			    " ioctl (get flags)");
9927c478bd9Sstevel@tonic-gate 			return (PI_IOCTL_ERROR);
9937c478bd9Sstevel@tonic-gate 		}
9947c478bd9Sstevel@tonic-gate 	}
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	pi->pi_flags = PHYINT_FLAGS(lifr.lifr_flags);
9977c478bd9Sstevel@tonic-gate 	if (pi->pi_v4 != NULL)
9987c478bd9Sstevel@tonic-gate 		pi->pi_v4->pii_flags = pi->pi_flags;
9997c478bd9Sstevel@tonic-gate 	if (pi->pi_v6 != NULL)
10007c478bd9Sstevel@tonic-gate 		pi->pi_v6->pii_flags = pi->pi_flags;
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	if (pi->pi_flags & IFF_FAILED) {
10037c478bd9Sstevel@tonic-gate 		/*
10047c478bd9Sstevel@tonic-gate 		 * If we are in the running and full state, we have
10057c478bd9Sstevel@tonic-gate 		 * completed failbacks successfully and we would have
10067c478bd9Sstevel@tonic-gate 		 * expected IFF_FAILED to have been clear. That it is
10077c478bd9Sstevel@tonic-gate 		 * set means there was a race condition. Some other
10087c478bd9Sstevel@tonic-gate 		 * process turned on the IFF_FAILED flag. Since the
10097c478bd9Sstevel@tonic-gate 		 * flag setting is not atomic, i.e. a get ioctl followed
10107c478bd9Sstevel@tonic-gate 		 * by a set ioctl, and since there is no way to set an
10117c478bd9Sstevel@tonic-gate 		 * individual flag bit, this could have occurred.
10127c478bd9Sstevel@tonic-gate 		 */
10137c478bd9Sstevel@tonic-gate 		if (pi->pi_state == PI_RUNNING && pi->pi_full)
10147c478bd9Sstevel@tonic-gate 			(void) change_lif_flags(pi, IFF_FAILED, _B_FALSE);
10157c478bd9Sstevel@tonic-gate 	} else {
10167c478bd9Sstevel@tonic-gate 		/*
10177c478bd9Sstevel@tonic-gate 		 * If we are in the failed state, there was a race.
10187c478bd9Sstevel@tonic-gate 		 * we have completed failover successfully because our
10197c478bd9Sstevel@tonic-gate 		 * state is failed and empty. Some other process turned
10207c478bd9Sstevel@tonic-gate 		 * off the IFF_FAILED flag. Same comment as above
10217c478bd9Sstevel@tonic-gate 		 */
10227c478bd9Sstevel@tonic-gate 		if (pi->pi_state == PI_FAILED && pi->pi_empty)
10237c478bd9Sstevel@tonic-gate 			(void) change_lif_flags(pi, IFF_FAILED, _B_TRUE);
10247c478bd9Sstevel@tonic-gate 	}
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	/* No change in phyint status */
10277c478bd9Sstevel@tonic-gate 	return (PI_OK);
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate /*
10317c478bd9Sstevel@tonic-gate  * Delete the phyint. Remove it from the list of all phyints, and the
10327c478bd9Sstevel@tonic-gate  * list of phyint group members. If the group becomes empty, delete the
10337c478bd9Sstevel@tonic-gate  * group also.
10347c478bd9Sstevel@tonic-gate  */
10357c478bd9Sstevel@tonic-gate static void
10367c478bd9Sstevel@tonic-gate phyint_delete(struct phyint *pi)
10377c478bd9Sstevel@tonic-gate {
10387c478bd9Sstevel@tonic-gate 	struct phyint_group *pg = pi->pi_group;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
10417c478bd9Sstevel@tonic-gate 		logdebug("phyint_delete(%s)\n", pi->pi_name);
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 	/* Both IPv4 and IPv6 phyint instances must have been deleted. */
10447c478bd9Sstevel@tonic-gate 	assert(pi->pi_v4 == NULL && pi->pi_v6 == NULL);
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	/*
10477c478bd9Sstevel@tonic-gate 	 * The phyint must belong to a group.
10487c478bd9Sstevel@tonic-gate 	 */
10497c478bd9Sstevel@tonic-gate 	assert(pg->pg_phyint == pi || pi->pi_pgprev != NULL);
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 	/* The phyint must be in the list of all phyints */
10527c478bd9Sstevel@tonic-gate 	assert(phyints == pi || pi->pi_prev != NULL);
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	/* Remove the phyint from the phyint group list */
10557c478bd9Sstevel@tonic-gate 	pg->pg_sig++;
10567c478bd9Sstevel@tonic-gate 	(void) phyint_group_member_event(pg, pi, IPMP_IF_REMOVE);
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	if (pi->pi_pgprev == NULL) {
10597c478bd9Sstevel@tonic-gate 		/* Phyint is the 1st in the phyint group list */
10607c478bd9Sstevel@tonic-gate 		pg->pg_phyint = pi->pi_pgnext;
10617c478bd9Sstevel@tonic-gate 	} else {
10627c478bd9Sstevel@tonic-gate 		pi->pi_pgprev->pi_pgnext = pi->pi_pgnext;
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate 	if (pi->pi_pgnext != NULL)
10657c478bd9Sstevel@tonic-gate 		pi->pi_pgnext->pi_pgprev = pi->pi_pgprev;
10667c478bd9Sstevel@tonic-gate 	pi->pi_pgnext = NULL;
10677c478bd9Sstevel@tonic-gate 	pi->pi_pgprev = NULL;
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	/* Remove the phyint from the global list of phyints */
10707c478bd9Sstevel@tonic-gate 	if (pi->pi_prev == NULL) {
10717c478bd9Sstevel@tonic-gate 		/* Phyint is the 1st in the list */
10727c478bd9Sstevel@tonic-gate 		phyints = pi->pi_next;
10737c478bd9Sstevel@tonic-gate 	} else {
10747c478bd9Sstevel@tonic-gate 		pi->pi_prev->pi_next = pi->pi_next;
10757c478bd9Sstevel@tonic-gate 	}
10767c478bd9Sstevel@tonic-gate 	if (pi->pi_next != NULL)
10777c478bd9Sstevel@tonic-gate 		pi->pi_next->pi_prev = pi->pi_prev;
10787c478bd9Sstevel@tonic-gate 	pi->pi_next = NULL;
10797c478bd9Sstevel@tonic-gate 	pi->pi_prev = NULL;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	free(pi);
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	/* Delete the phyint_group if the last phyint has been deleted */
10847c478bd9Sstevel@tonic-gate 	if (pg->pg_phyint == NULL)
10857c478bd9Sstevel@tonic-gate 		phyint_group_delete(pg);
10867c478bd9Sstevel@tonic-gate }
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate /*
10897c478bd9Sstevel@tonic-gate  * Delete (unlink and free), the phyint instance.
10907c478bd9Sstevel@tonic-gate  */
10917c478bd9Sstevel@tonic-gate void
10927c478bd9Sstevel@tonic-gate phyint_inst_delete(struct phyint_instance *pii)
10937c478bd9Sstevel@tonic-gate {
10947c478bd9Sstevel@tonic-gate 	struct phyint *pi = pii->pii_phyint;
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 	assert(pi != NULL);
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
10997c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_delete(%s %s)\n",
11007c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pi->pi_name);
11017c478bd9Sstevel@tonic-gate 	}
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	/*
11047c478bd9Sstevel@tonic-gate 	 * If the phyint instance has associated probe targets
11057c478bd9Sstevel@tonic-gate 	 * delete all the targets
11067c478bd9Sstevel@tonic-gate 	 */
11077c478bd9Sstevel@tonic-gate 	while (pii->pii_targets != NULL)
11087c478bd9Sstevel@tonic-gate 		target_delete(pii->pii_targets);
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	/*
11117c478bd9Sstevel@tonic-gate 	 * Delete all the logints associated with this phyint
11127c478bd9Sstevel@tonic-gate 	 * instance.
11137c478bd9Sstevel@tonic-gate 	 */
11147c478bd9Sstevel@tonic-gate 	while (pii->pii_logint != NULL)
11157c478bd9Sstevel@tonic-gate 		logint_delete(pii->pii_logint);
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	/*
1118*921e7e07Smeem 	 * Close the socket used to send probes to targets from this phyint.
11197c478bd9Sstevel@tonic-gate 	 */
11207c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock != -1)
11217c478bd9Sstevel@tonic-gate 		close_probe_socket(pii, _B_TRUE);
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	/*
11247c478bd9Sstevel@tonic-gate 	 * Phyint instance must be in the list of all phyint instances.
11257c478bd9Sstevel@tonic-gate 	 * Remove phyint instance from the global list of phyint instances.
11267c478bd9Sstevel@tonic-gate 	 */
11277c478bd9Sstevel@tonic-gate 	assert(phyint_instances == pii || pii->pii_prev != NULL);
11287c478bd9Sstevel@tonic-gate 	if (pii->pii_prev == NULL) {
11297c478bd9Sstevel@tonic-gate 		/* Phyint is the 1st in the list */
11307c478bd9Sstevel@tonic-gate 		phyint_instances = pii->pii_next;
11317c478bd9Sstevel@tonic-gate 	} else {
11327c478bd9Sstevel@tonic-gate 		pii->pii_prev->pii_next = pii->pii_next;
11337c478bd9Sstevel@tonic-gate 	}
11347c478bd9Sstevel@tonic-gate 	if (pii->pii_next != NULL)
11357c478bd9Sstevel@tonic-gate 		pii->pii_next->pii_prev = pii->pii_prev;
11367c478bd9Sstevel@tonic-gate 	pii->pii_next = NULL;
11377c478bd9Sstevel@tonic-gate 	pii->pii_prev = NULL;
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	/*
11407c478bd9Sstevel@tonic-gate 	 * Reset the phyint instance pointer in the phyint.
11417c478bd9Sstevel@tonic-gate 	 * If this is the last phyint instance (being deleted) on this
11427c478bd9Sstevel@tonic-gate 	 * phyint, then delete the phyint.
11437c478bd9Sstevel@tonic-gate 	 */
11447c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET)
11457c478bd9Sstevel@tonic-gate 		pi->pi_v4 = NULL;
11467c478bd9Sstevel@tonic-gate 	else
11477c478bd9Sstevel@tonic-gate 		pi->pi_v6 = NULL;
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	if (pi->pi_v4 == NULL && pi->pi_v6 == NULL)
11507c478bd9Sstevel@tonic-gate 		phyint_delete(pi);
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	free(pii);
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate static void
11567c478bd9Sstevel@tonic-gate phyint_inst_print(struct phyint_instance *pii)
11577c478bd9Sstevel@tonic-gate {
11587c478bd9Sstevel@tonic-gate 	struct logint *li;
11597c478bd9Sstevel@tonic-gate 	struct target *tg;
11607c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
11617c478bd9Sstevel@tonic-gate 	int most_recent;
11627c478bd9Sstevel@tonic-gate 	int i;
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	if (pii->pii_phyint == NULL) {
11657c478bd9Sstevel@tonic-gate 		logdebug("pii->pi_phyint NULL can't print\n");
11667c478bd9Sstevel@tonic-gate 		return;
11677c478bd9Sstevel@tonic-gate 	}
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	logdebug("\nPhyint instance: %s %s index %u state %x flags %llx	 "
11707c478bd9Sstevel@tonic-gate 	    "sock %x in_use %d empty %x full %x\n",
11717c478bd9Sstevel@tonic-gate 	    AF_STR(pii->pii_af), pii->pii_name, pii->pii_ifindex,
11727c478bd9Sstevel@tonic-gate 	    pii->pii_state, pii->pii_phyint->pi_flags, pii->pii_probe_sock,
11737c478bd9Sstevel@tonic-gate 	    pii->pii_in_use, pii->pii_phyint->pi_empty,
11747c478bd9Sstevel@tonic-gate 	    pii->pii_phyint->pi_full);
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	for (li = pii->pii_logint; li != NULL; li = li->li_next)
11777c478bd9Sstevel@tonic-gate 		logint_print(li);
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	logdebug("\n");
11807c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next)
11817c478bd9Sstevel@tonic-gate 		target_print(tg);
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	if (pii->pii_targets == NULL)
11847c478bd9Sstevel@tonic-gate 		logdebug("pi_targets NULL\n");
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	if (pii->pii_target_next != NULL) {
11877c478bd9Sstevel@tonic-gate 		logdebug("pi_target_next %s %s\n", AF_STR(pii->pii_af),
11887c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, pii->pii_target_next->tg_address,
11897c478bd9Sstevel@tonic-gate 			abuf, sizeof (abuf)));
11907c478bd9Sstevel@tonic-gate 	} else {
11917c478bd9Sstevel@tonic-gate 		logdebug("pi_target_next NULL\n");
11927c478bd9Sstevel@tonic-gate 	}
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	if (pii->pii_rtt_target_next != NULL) {
11957c478bd9Sstevel@tonic-gate 		logdebug("pi_rtt_target_next %s %s\n", AF_STR(pii->pii_af),
11967c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, pii->pii_rtt_target_next->tg_address,
11977c478bd9Sstevel@tonic-gate 			abuf, sizeof (abuf)));
11987c478bd9Sstevel@tonic-gate 	} else {
11997c478bd9Sstevel@tonic-gate 		logdebug("pi_rtt_target_next NULL\n");
12007c478bd9Sstevel@tonic-gate 	}
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	if (pii->pii_targets != NULL) {
12037c478bd9Sstevel@tonic-gate 		most_recent = PROBE_INDEX_PREV(pii->pii_probe_next);
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 		i = most_recent;
12067c478bd9Sstevel@tonic-gate 		do {
12077c478bd9Sstevel@tonic-gate 			if (pii->pii_probes[i].pr_target != NULL) {
12087c478bd9Sstevel@tonic-gate 				logdebug("#%d target %s ", i,
12097c478bd9Sstevel@tonic-gate 				    pr_addr(pii->pii_af,
12107c478bd9Sstevel@tonic-gate 				    pii->pii_probes[i].pr_target->tg_address,
12117c478bd9Sstevel@tonic-gate 				    abuf, sizeof (abuf)));
12127c478bd9Sstevel@tonic-gate 			} else {
12137c478bd9Sstevel@tonic-gate 				logdebug("#%d target NULL ", i);
12147c478bd9Sstevel@tonic-gate 			}
12157c478bd9Sstevel@tonic-gate 			logdebug("time_sent %u status %d time_ack/lost %u\n",
12167c478bd9Sstevel@tonic-gate 			    pii->pii_probes[i].pr_time_sent,
12177c478bd9Sstevel@tonic-gate 			    pii->pii_probes[i].pr_status,
12187c478bd9Sstevel@tonic-gate 			    pii->pii_probes[i].pr_time_lost);
12197c478bd9Sstevel@tonic-gate 			i = PROBE_INDEX_PREV(i);
12207c478bd9Sstevel@tonic-gate 		} while (i != most_recent);
12217c478bd9Sstevel@tonic-gate 	}
12227c478bd9Sstevel@tonic-gate }
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate /*
12257c478bd9Sstevel@tonic-gate  * Lookup a logint based on the logical interface name, on the given
12267c478bd9Sstevel@tonic-gate  * phyint instance.
12277c478bd9Sstevel@tonic-gate  */
12287c478bd9Sstevel@tonic-gate static struct logint *
12297c478bd9Sstevel@tonic-gate logint_lookup(struct phyint_instance *pii, char *name)
12307c478bd9Sstevel@tonic-gate {
12317c478bd9Sstevel@tonic-gate 	struct logint *li;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
12347c478bd9Sstevel@tonic-gate 		logdebug("logint_lookup(%s, %s)\n",
12357c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), name);
12367c478bd9Sstevel@tonic-gate 	}
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	for (li = pii->pii_logint; li != NULL; li = li->li_next) {
12397c478bd9Sstevel@tonic-gate 		if (strncmp(name, li->li_name, sizeof (li->li_name)) == 0)
12407c478bd9Sstevel@tonic-gate 			break;
12417c478bd9Sstevel@tonic-gate 	}
12427c478bd9Sstevel@tonic-gate 	return (li);
12437c478bd9Sstevel@tonic-gate }
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate /*
12467c478bd9Sstevel@tonic-gate  * Insert a logint at the head of the list of logints of the given
12477c478bd9Sstevel@tonic-gate  * phyint instance
12487c478bd9Sstevel@tonic-gate  */
12497c478bd9Sstevel@tonic-gate static void
12507c478bd9Sstevel@tonic-gate logint_insert(struct phyint_instance *pii, struct logint *li)
12517c478bd9Sstevel@tonic-gate {
12527c478bd9Sstevel@tonic-gate 	li->li_next = pii->pii_logint;
12537c478bd9Sstevel@tonic-gate 	li->li_prev = NULL;
12547c478bd9Sstevel@tonic-gate 	if (pii->pii_logint != NULL)
12557c478bd9Sstevel@tonic-gate 		pii->pii_logint->li_prev = li;
12567c478bd9Sstevel@tonic-gate 	pii->pii_logint = li;
12577c478bd9Sstevel@tonic-gate 	li->li_phyint_inst = pii;
12587c478bd9Sstevel@tonic-gate }
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate /*
12617c478bd9Sstevel@tonic-gate  * Create a new named logint, on the specified phyint instance.
12627c478bd9Sstevel@tonic-gate  */
12637c478bd9Sstevel@tonic-gate static struct logint *
12647c478bd9Sstevel@tonic-gate logint_create(struct phyint_instance *pii, char *name)
12657c478bd9Sstevel@tonic-gate {
12667c478bd9Sstevel@tonic-gate 	struct logint *li;
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
12697c478bd9Sstevel@tonic-gate 		logdebug("logint_create(%s %s %s)\n",
12707c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name, name);
12717c478bd9Sstevel@tonic-gate 	}
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	li = calloc(1, sizeof (struct logint));
12747c478bd9Sstevel@tonic-gate 	if (li == NULL) {
12757c478bd9Sstevel@tonic-gate 		logperror("logint_create: calloc");
12767c478bd9Sstevel@tonic-gate 		return (NULL);
12777c478bd9Sstevel@tonic-gate 	}
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate 	(void) strncpy(li->li_name, name, sizeof (li->li_name));
12807c478bd9Sstevel@tonic-gate 	li->li_name[sizeof (li->li_name) - 1] = '\0';
12817c478bd9Sstevel@tonic-gate 	logint_insert(pii, li);
12827c478bd9Sstevel@tonic-gate 	return (li);
12837c478bd9Sstevel@tonic-gate }
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate /*
12867c478bd9Sstevel@tonic-gate  * Initialize the logint based on the data returned by the kernel.
12877c478bd9Sstevel@tonic-gate  */
12887c478bd9Sstevel@tonic-gate void
12897c478bd9Sstevel@tonic-gate logint_init_from_k(struct phyint_instance *pii, char *li_name)
12907c478bd9Sstevel@tonic-gate {
12917c478bd9Sstevel@tonic-gate 	int	ifsock;
12927c478bd9Sstevel@tonic-gate 	uint64_t flags;
12937c478bd9Sstevel@tonic-gate 	uint64_t saved_flags;
12947c478bd9Sstevel@tonic-gate 	struct	logint	*li;
12957c478bd9Sstevel@tonic-gate 	struct lifreq	lifr;
12967c478bd9Sstevel@tonic-gate 	struct in6_addr	test_subnet;
12977c478bd9Sstevel@tonic-gate 	struct in6_addr	test_subnet_mask;
12987c478bd9Sstevel@tonic-gate 	struct in6_addr	testaddr;
12997c478bd9Sstevel@tonic-gate 	int	test_subnet_len;
13007c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
13017c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin;
13027c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
13037c478bd9Sstevel@tonic-gate 	boolean_t  ptp = _B_FALSE;
13047c478bd9Sstevel@tonic-gate 	struct in6_addr tgaddr;
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
13077c478bd9Sstevel@tonic-gate 		logdebug("logint_init_from_k(%s %s)\n",
13087c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), li_name);
13097c478bd9Sstevel@tonic-gate 	}
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	/* Get the socket for doing ioctls */
13127c478bd9Sstevel@tonic-gate 	ifsock = (pii->pii_af == AF_INET) ? ifsock_v4 : ifsock_v6;
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	/*
13157c478bd9Sstevel@tonic-gate 	 * Get the flags from the kernel. Also serves as a check whether
13167c478bd9Sstevel@tonic-gate 	 * the logical still exists. If it doesn't exist, no need to proceed
13177c478bd9Sstevel@tonic-gate 	 * any further. li_in_use will make the caller clean up the logint
13187c478bd9Sstevel@tonic-gate 	 */
13197c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, li_name, sizeof (lifr.lifr_name));
13207c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
13217c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
13227c478bd9Sstevel@tonic-gate 		/* Interface may have vanished */
13237c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
13247c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "logint_init_from_k: "
13257c478bd9Sstevel@tonic-gate 			    "ioctl (get flags)");
13267c478bd9Sstevel@tonic-gate 		}
13277c478bd9Sstevel@tonic-gate 		return;
13287c478bd9Sstevel@tonic-gate 	}
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	flags = lifr.lifr_flags;
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	/*
13337c478bd9Sstevel@tonic-gate 	 * Verified the logint exists. Now lookup the logint in our tables.
13347c478bd9Sstevel@tonic-gate 	 * If it does not exist, create a new logint.
13357c478bd9Sstevel@tonic-gate 	 */
13367c478bd9Sstevel@tonic-gate 	li = logint_lookup(pii, li_name);
13377c478bd9Sstevel@tonic-gate 	if (li == NULL) {
13387c478bd9Sstevel@tonic-gate 		li = logint_create(pii, li_name);
13397c478bd9Sstevel@tonic-gate 		if (li == NULL) {
13407c478bd9Sstevel@tonic-gate 			/*
13417c478bd9Sstevel@tonic-gate 			 * Pretend the interface does not exist
13427c478bd9Sstevel@tonic-gate 			 * in the kernel
13437c478bd9Sstevel@tonic-gate 			 */
13447c478bd9Sstevel@tonic-gate 			return;
13457c478bd9Sstevel@tonic-gate 		}
13467c478bd9Sstevel@tonic-gate 	}
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	/*
13497c478bd9Sstevel@tonic-gate 	 * Update li->li_flags with the new flags, after saving the old
13507c478bd9Sstevel@tonic-gate 	 * value. This is used later to check what flags has changed and
13517c478bd9Sstevel@tonic-gate 	 * take any action
13527c478bd9Sstevel@tonic-gate 	 */
13537c478bd9Sstevel@tonic-gate 	saved_flags = li->li_flags;
13547c478bd9Sstevel@tonic-gate 	li->li_flags = flags;
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 	/*
13577c478bd9Sstevel@tonic-gate 	 * Get the address, prefix, prefixlength and update the logint.
13587c478bd9Sstevel@tonic-gate 	 * Check if anything has changed. If the logint used for the
13597c478bd9Sstevel@tonic-gate 	 * test address has changed, take suitable action.
13607c478bd9Sstevel@tonic-gate 	 */
13617c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFADDR, (char *)&lifr) < 0) {
13627c478bd9Sstevel@tonic-gate 		/* Interface may have vanished */
13637c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
13647c478bd9Sstevel@tonic-gate 			logperror_li(li, "logint_init_from_k: (get addr)");
13657c478bd9Sstevel@tonic-gate 		}
13667c478bd9Sstevel@tonic-gate 		goto error;
13677c478bd9Sstevel@tonic-gate 	}
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET) {
13707c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
13717c478bd9Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &testaddr);
13727c478bd9Sstevel@tonic-gate 	} else {
13737c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
13747c478bd9Sstevel@tonic-gate 		testaddr = sin6->sin6_addr;
13757c478bd9Sstevel@tonic-gate 	}
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	if (pii->pii_phyint->pi_flags & IFF_POINTOPOINT) {
13787c478bd9Sstevel@tonic-gate 		ptp = _B_TRUE;
13797c478bd9Sstevel@tonic-gate 		if (ioctl(ifsock, SIOCGLIFDSTADDR, (char *)&lifr) < 0) {
13807c478bd9Sstevel@tonic-gate 			if (errno != ENXIO) {
13817c478bd9Sstevel@tonic-gate 				logperror_li(li, "logint_init_from_k:"
13827c478bd9Sstevel@tonic-gate 				    " (get dstaddr)");
13837c478bd9Sstevel@tonic-gate 			}
13847c478bd9Sstevel@tonic-gate 			goto error;
13857c478bd9Sstevel@tonic-gate 		}
13867c478bd9Sstevel@tonic-gate 		if (pii->pii_af == AF_INET) {
13877c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&lifr.lifr_addr;
13887c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &tgaddr);
13897c478bd9Sstevel@tonic-gate 		} else {
13907c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
13917c478bd9Sstevel@tonic-gate 			tgaddr = sin6->sin6_addr;
13927c478bd9Sstevel@tonic-gate 		}
13937c478bd9Sstevel@tonic-gate 	} else {
13947c478bd9Sstevel@tonic-gate 		if (ioctl(ifsock, SIOCGLIFSUBNET, (char *)&lifr) < 0) {
13957c478bd9Sstevel@tonic-gate 			/* Interface may have vanished */
13967c478bd9Sstevel@tonic-gate 			if (errno != ENXIO) {
13977c478bd9Sstevel@tonic-gate 				logperror_li(li, "logint_init_from_k:"
13987c478bd9Sstevel@tonic-gate 				    " (get subnet)");
13997c478bd9Sstevel@tonic-gate 			}
14007c478bd9Sstevel@tonic-gate 			goto error;
14017c478bd9Sstevel@tonic-gate 		}
14027c478bd9Sstevel@tonic-gate 		if (lifr.lifr_subnet.ss_family == AF_INET6) {
14037c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)&lifr.lifr_subnet;
14047c478bd9Sstevel@tonic-gate 			test_subnet = sin6->sin6_addr;
14057c478bd9Sstevel@tonic-gate 			test_subnet_len = lifr.lifr_addrlen;
14067c478bd9Sstevel@tonic-gate 		} else {
14077c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&lifr.lifr_subnet;
14087c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &test_subnet);
14097c478bd9Sstevel@tonic-gate 			test_subnet_len = lifr.lifr_addrlen +
14107c478bd9Sstevel@tonic-gate 			    (IPV6_ABITS - IP_ABITS);
14117c478bd9Sstevel@tonic-gate 		}
14127c478bd9Sstevel@tonic-gate 		(void) ip_index_to_mask_v6(test_subnet_len, &test_subnet_mask);
14137c478bd9Sstevel@tonic-gate 	}
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 	/*
14167c478bd9Sstevel@tonic-gate 	 * Also record the OINDEX for completeness. This information is
14177c478bd9Sstevel@tonic-gate 	 * not used.
14187c478bd9Sstevel@tonic-gate 	 */
14197c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFOINDEX, (char *)&lifr) < 0) {
14207c478bd9Sstevel@tonic-gate 		if (errno != ENXIO)  {
14217c478bd9Sstevel@tonic-gate 			logperror_li(li, "logint_init_from_k:"
14227c478bd9Sstevel@tonic-gate 			    " (get lifoindex)");
14237c478bd9Sstevel@tonic-gate 		}
14247c478bd9Sstevel@tonic-gate 		goto error;
14257c478bd9Sstevel@tonic-gate 	}
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 	/*
14287c478bd9Sstevel@tonic-gate 	 * If this is the logint corresponding to the test address used for
14297c478bd9Sstevel@tonic-gate 	 * sending probes, then if anything significant has changed we need to
14307c478bd9Sstevel@tonic-gate 	 * determine the test address again.  We ignore changes to the
14317c478bd9Sstevel@tonic-gate 	 * IFF_FAILED and IFF_RUNNING flags since those happen as a matter of
14327c478bd9Sstevel@tonic-gate 	 * course.
14337c478bd9Sstevel@tonic-gate 	 */
14347c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_logint == li) {
14357c478bd9Sstevel@tonic-gate 		if (((li->li_flags ^ saved_flags) &
14367c478bd9Sstevel@tonic-gate 		    ~(IFF_FAILED | IFF_RUNNING)) != 0 ||
14377c478bd9Sstevel@tonic-gate 		    !IN6_ARE_ADDR_EQUAL(&testaddr, &li->li_addr) ||
14387c478bd9Sstevel@tonic-gate 		    (!ptp && !IN6_ARE_ADDR_EQUAL(&test_subnet,
14397c478bd9Sstevel@tonic-gate 			&li->li_subnet)) ||
14407c478bd9Sstevel@tonic-gate 		    (!ptp && test_subnet_len != li->li_subnet_len) ||
14417c478bd9Sstevel@tonic-gate 		    (ptp && !IN6_ARE_ADDR_EQUAL(&tgaddr, &li->li_dstaddr))) {
14427c478bd9Sstevel@tonic-gate 			/*
14437c478bd9Sstevel@tonic-gate 			 * Something significant that affects the testaddress
14447c478bd9Sstevel@tonic-gate 			 * has changed. Redo the testaddress selection later on
14457c478bd9Sstevel@tonic-gate 			 * in select_test_ifs(). For now do the cleanup and
14467c478bd9Sstevel@tonic-gate 			 * set pii_probe_logint to NULL.
14477c478bd9Sstevel@tonic-gate 			 */
14487c478bd9Sstevel@tonic-gate 			if (pii->pii_probe_sock != -1)
14497c478bd9Sstevel@tonic-gate 				close_probe_socket(pii, _B_TRUE);
14507c478bd9Sstevel@tonic-gate 			pii->pii_probe_logint = NULL;
14517c478bd9Sstevel@tonic-gate 		}
14527c478bd9Sstevel@tonic-gate 	}
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 	/* Update the logint with the values obtained from the kernel.	*/
14567c478bd9Sstevel@tonic-gate 	li->li_addr = testaddr;
14577c478bd9Sstevel@tonic-gate 	li->li_in_use = 1;
14587c478bd9Sstevel@tonic-gate 	li->li_oifindex = lifr.lifr_index;
14597c478bd9Sstevel@tonic-gate 	if (ptp) {
14607c478bd9Sstevel@tonic-gate 		li->li_dstaddr = tgaddr;
14617c478bd9Sstevel@tonic-gate 		li->li_subnet_len = (pii->pii_af == AF_INET) ?
14627c478bd9Sstevel@tonic-gate 		    IP_ABITS : IPV6_ABITS;
14637c478bd9Sstevel@tonic-gate 	} else {
14647c478bd9Sstevel@tonic-gate 		li->li_subnet = test_subnet;
14657c478bd9Sstevel@tonic-gate 		li->li_subnet_len = test_subnet_len;
14667c478bd9Sstevel@tonic-gate 	}
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT)
14697c478bd9Sstevel@tonic-gate 		logint_print(li);
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	return;
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate error:
14747c478bd9Sstevel@tonic-gate 	logerr("logint_init_from_k: IGNORED %s %s %s addr %s\n",
14757c478bd9Sstevel@tonic-gate 	    AF_STR(pii->pii_af), pii->pii_name, li->li_name,
14767c478bd9Sstevel@tonic-gate 	    pr_addr(pii->pii_af, testaddr, abuf, sizeof (abuf)));
14777c478bd9Sstevel@tonic-gate 	logint_delete(li);
14787c478bd9Sstevel@tonic-gate }
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate /*
14817c478bd9Sstevel@tonic-gate  * Delete (unlink and free) a logint.
14827c478bd9Sstevel@tonic-gate  */
14837c478bd9Sstevel@tonic-gate void
14847c478bd9Sstevel@tonic-gate logint_delete(struct logint *li)
14857c478bd9Sstevel@tonic-gate {
14867c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	pii = li->li_phyint_inst;
14897c478bd9Sstevel@tonic-gate 	assert(pii != NULL);
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
14927c478bd9Sstevel@tonic-gate 		int af;
14937c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 		af = pii->pii_af;
14967c478bd9Sstevel@tonic-gate 		logdebug("logint_delete(%s %s %s/%u)\n",
14977c478bd9Sstevel@tonic-gate 		    AF_STR(af), li->li_name,
14987c478bd9Sstevel@tonic-gate 		    pr_addr(af, li->li_addr, abuf, sizeof (abuf)),
14997c478bd9Sstevel@tonic-gate 		    li->li_subnet_len);
15007c478bd9Sstevel@tonic-gate 	}
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate 	/* logint must be in the list of logints */
15037c478bd9Sstevel@tonic-gate 	assert(pii->pii_logint == li || li->li_prev != NULL);
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	/* Remove the logint from the list of logints  */
15067c478bd9Sstevel@tonic-gate 	if (li->li_prev == NULL) {
15077c478bd9Sstevel@tonic-gate 		/* logint is the 1st in the list */
15087c478bd9Sstevel@tonic-gate 		pii->pii_logint = li->li_next;
15097c478bd9Sstevel@tonic-gate 	} else {
15107c478bd9Sstevel@tonic-gate 		li->li_prev->li_next = li->li_next;
15117c478bd9Sstevel@tonic-gate 	}
15127c478bd9Sstevel@tonic-gate 	if (li->li_next != NULL)
15137c478bd9Sstevel@tonic-gate 		li->li_next->li_prev = li->li_prev;
15147c478bd9Sstevel@tonic-gate 	li->li_next = NULL;
15157c478bd9Sstevel@tonic-gate 	li->li_prev = NULL;
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	/*
1518*921e7e07Smeem 	 * If this logint is also being used for probing, then close the
1519*921e7e07Smeem 	 * associated socket, if it exists.
15207c478bd9Sstevel@tonic-gate 	 */
15217c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_logint == li) {
15227c478bd9Sstevel@tonic-gate 		if (pii->pii_probe_sock != -1)
15237c478bd9Sstevel@tonic-gate 			close_probe_socket(pii, _B_TRUE);
15247c478bd9Sstevel@tonic-gate 		pii->pii_probe_logint = NULL;
15257c478bd9Sstevel@tonic-gate 	}
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	free(li);
15287c478bd9Sstevel@tonic-gate }
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate static void
15317c478bd9Sstevel@tonic-gate logint_print(struct logint *li)
15327c478bd9Sstevel@tonic-gate {
15337c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
15347c478bd9Sstevel@tonic-gate 	int af;
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 	af = li->li_phyint_inst->pii_af;
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	logdebug("logint: %s %s addr %s/%u", AF_STR(af), li->li_name,
15397c478bd9Sstevel@tonic-gate 	    pr_addr(af, li->li_addr, abuf, sizeof (abuf)), li->li_subnet_len);
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 	logdebug("\tFlags: %llx in_use %d oifindex %d\n",
15427c478bd9Sstevel@tonic-gate 	    li->li_flags, li->li_in_use, li->li_oifindex);
15437c478bd9Sstevel@tonic-gate }
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate char *
15467c478bd9Sstevel@tonic-gate pr_addr(int af, struct in6_addr addr, char *abuf, int len)
15477c478bd9Sstevel@tonic-gate {
15487c478bd9Sstevel@tonic-gate 	struct in_addr	addr_v4;
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
15517c478bd9Sstevel@tonic-gate 		IN6_V4MAPPED_TO_INADDR(&addr, &addr_v4);
15527c478bd9Sstevel@tonic-gate 		(void) inet_ntop(AF_INET, (void *)&addr_v4, abuf, len);
15537c478bd9Sstevel@tonic-gate 	} else {
15547c478bd9Sstevel@tonic-gate 		(void) inet_ntop(AF_INET6, (void *)&addr, abuf, len);
15557c478bd9Sstevel@tonic-gate 	}
15567c478bd9Sstevel@tonic-gate 	return (abuf);
15577c478bd9Sstevel@tonic-gate }
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate /* Lookup target on its address */
15607c478bd9Sstevel@tonic-gate struct target *
15617c478bd9Sstevel@tonic-gate target_lookup(struct phyint_instance *pii, struct in6_addr addr)
15627c478bd9Sstevel@tonic-gate {
15637c478bd9Sstevel@tonic-gate 	struct target *tg;
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET) {
15667c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 		logdebug("target_lookup(%s %s): addr %s\n",
15697c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name,
15707c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, addr, abuf, sizeof (abuf)));
15717c478bd9Sstevel@tonic-gate 	}
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) {
15747c478bd9Sstevel@tonic-gate 		if (IN6_ARE_ADDR_EQUAL(&tg->tg_address, &addr))
15757c478bd9Sstevel@tonic-gate 			break;
15767c478bd9Sstevel@tonic-gate 	}
15777c478bd9Sstevel@tonic-gate 	return (tg);
15787c478bd9Sstevel@tonic-gate }
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate /*
15817c478bd9Sstevel@tonic-gate  * Find and return the next active target, for the next probe.
15827c478bd9Sstevel@tonic-gate  * If no active targets are available, return NULL.
15837c478bd9Sstevel@tonic-gate  */
15847c478bd9Sstevel@tonic-gate struct target *
15857c478bd9Sstevel@tonic-gate target_next(struct target *tg)
15867c478bd9Sstevel@tonic-gate {
15877c478bd9Sstevel@tonic-gate 	struct	phyint_instance	*pii = tg->tg_phyint_inst;
15887c478bd9Sstevel@tonic-gate 	struct	target	*marker = tg;
15897c478bd9Sstevel@tonic-gate 	hrtime_t now;
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate 	now = gethrtime();
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 	/*
15947c478bd9Sstevel@tonic-gate 	 * Target must be in the list of targets for this phyint
15957c478bd9Sstevel@tonic-gate 	 * instance.
15967c478bd9Sstevel@tonic-gate 	 */
15977c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets == tg || tg->tg_prev != NULL);
15987c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets != NULL);
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	/* Return the next active target */
16017c478bd9Sstevel@tonic-gate 	do {
16027c478bd9Sstevel@tonic-gate 		/*
16037c478bd9Sstevel@tonic-gate 		 * Go to the next target. If we hit the end,
16047c478bd9Sstevel@tonic-gate 		 * reset the ptr to the head
16057c478bd9Sstevel@tonic-gate 		 */
16067c478bd9Sstevel@tonic-gate 		tg = tg->tg_next;
16077c478bd9Sstevel@tonic-gate 		if (tg == NULL)
16087c478bd9Sstevel@tonic-gate 			tg = pii->pii_targets;
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 		switch (tg->tg_status) {
16137c478bd9Sstevel@tonic-gate 		case TG_ACTIVE:
16147c478bd9Sstevel@tonic-gate 			return (tg);
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate 		case TG_UNUSED:
16177c478bd9Sstevel@tonic-gate 			assert(pii->pii_targets_are_routers);
16187c478bd9Sstevel@tonic-gate 			if (pii->pii_ntargets < MAX_PROBE_TARGETS) {
16197c478bd9Sstevel@tonic-gate 				/*
16207c478bd9Sstevel@tonic-gate 				 * Bubble up the unused target to active
16217c478bd9Sstevel@tonic-gate 				 */
16227c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_ACTIVE;
16237c478bd9Sstevel@tonic-gate 				pii->pii_ntargets++;
16247c478bd9Sstevel@tonic-gate 				return (tg);
16257c478bd9Sstevel@tonic-gate 			}
16267c478bd9Sstevel@tonic-gate 			break;
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 		case TG_SLOW:
16297c478bd9Sstevel@tonic-gate 			assert(pii->pii_targets_are_routers);
16307c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
16317c478bd9Sstevel@tonic-gate 				/*
16327c478bd9Sstevel@tonic-gate 				 * Bubble up the slow target to unused
16337c478bd9Sstevel@tonic-gate 				 */
16347c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_UNUSED;
16357c478bd9Sstevel@tonic-gate 			}
16367c478bd9Sstevel@tonic-gate 			break;
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 		case TG_DEAD:
16397c478bd9Sstevel@tonic-gate 			assert(pii->pii_targets_are_routers);
16407c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
16417c478bd9Sstevel@tonic-gate 				/*
16427c478bd9Sstevel@tonic-gate 				 * Bubble up the dead target to slow
16437c478bd9Sstevel@tonic-gate 				 */
16447c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_SLOW;
16457c478bd9Sstevel@tonic-gate 				tg->tg_latime = now;
16467c478bd9Sstevel@tonic-gate 			}
16477c478bd9Sstevel@tonic-gate 			break;
16487c478bd9Sstevel@tonic-gate 		}
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	} while (tg != marker);
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 	return (NULL);
16537c478bd9Sstevel@tonic-gate }
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate /*
16567c478bd9Sstevel@tonic-gate  * Select the best available target, that is not already TG_ACTIVE,
16577c478bd9Sstevel@tonic-gate  * for the caller. The caller will determine whether it wants to
16587c478bd9Sstevel@tonic-gate  * make the returned target TG_ACTIVE.
16597c478bd9Sstevel@tonic-gate  * The selection order is as follows.
16607c478bd9Sstevel@tonic-gate  * 1. pick a TG_UNSED target, if it exists.
16617c478bd9Sstevel@tonic-gate  * 2. else pick a TG_SLOW target that has recovered, if it exists
16627c478bd9Sstevel@tonic-gate  * 3. else pick any TG_SLOW target, if it exists
16637c478bd9Sstevel@tonic-gate  * 4. else pick a TG_DEAD target that has recovered, if it exists
16647c478bd9Sstevel@tonic-gate  * 5. else pick any TG_DEAD target, if it exists
16657c478bd9Sstevel@tonic-gate  * 6. else return null
16667c478bd9Sstevel@tonic-gate  */
16677c478bd9Sstevel@tonic-gate static struct target *
16687c478bd9Sstevel@tonic-gate target_select_best(struct phyint_instance *pii)
16697c478bd9Sstevel@tonic-gate {
16707c478bd9Sstevel@tonic-gate 	struct target *tg;
16717c478bd9Sstevel@tonic-gate 	struct target *slow = NULL;
16727c478bd9Sstevel@tonic-gate 	struct target *dead = NULL;
16737c478bd9Sstevel@tonic-gate 	struct target *slow_recovered = NULL;
16747c478bd9Sstevel@tonic-gate 	struct target *dead_recovered = NULL;
16757c478bd9Sstevel@tonic-gate 	hrtime_t now;
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 	now = gethrtime();
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) {
16807c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 		switch (tg->tg_status) {
16837c478bd9Sstevel@tonic-gate 		case TG_UNUSED:
16847c478bd9Sstevel@tonic-gate 			return (tg);
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 		case TG_SLOW:
16877c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
16887c478bd9Sstevel@tonic-gate 				slow_recovered = tg;
16897c478bd9Sstevel@tonic-gate 				/*
16907c478bd9Sstevel@tonic-gate 				 * Promote the slow_recoverd to unused
16917c478bd9Sstevel@tonic-gate 				 */
16927c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_UNUSED;
16937c478bd9Sstevel@tonic-gate 			} else {
16947c478bd9Sstevel@tonic-gate 				slow = tg;
16957c478bd9Sstevel@tonic-gate 			}
16967c478bd9Sstevel@tonic-gate 			break;
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate 		case TG_DEAD:
16997c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
17007c478bd9Sstevel@tonic-gate 				dead_recovered = tg;
17017c478bd9Sstevel@tonic-gate 				/*
17027c478bd9Sstevel@tonic-gate 				 * Promote the dead_recoverd to slow
17037c478bd9Sstevel@tonic-gate 				 */
17047c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_SLOW;
17057c478bd9Sstevel@tonic-gate 				tg->tg_latime = now;
17067c478bd9Sstevel@tonic-gate 			} else {
17077c478bd9Sstevel@tonic-gate 				dead = tg;
17087c478bd9Sstevel@tonic-gate 			}
17097c478bd9Sstevel@tonic-gate 			break;
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 		default:
17127c478bd9Sstevel@tonic-gate 			break;
17137c478bd9Sstevel@tonic-gate 		}
17147c478bd9Sstevel@tonic-gate 	}
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	if (slow_recovered != NULL)
17177c478bd9Sstevel@tonic-gate 		return (slow_recovered);
17187c478bd9Sstevel@tonic-gate 	else if (slow != NULL)
17197c478bd9Sstevel@tonic-gate 		return (slow);
17207c478bd9Sstevel@tonic-gate 	else if (dead_recovered != NULL)
17217c478bd9Sstevel@tonic-gate 		return (dead_recovered);
17227c478bd9Sstevel@tonic-gate 	else
17237c478bd9Sstevel@tonic-gate 		return (dead);
17247c478bd9Sstevel@tonic-gate }
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate /*
17277c478bd9Sstevel@tonic-gate  * Some target was deleted. If we don't have even MIN_PROBE_TARGETS
17287c478bd9Sstevel@tonic-gate  * that are active, pick the next best below.
17297c478bd9Sstevel@tonic-gate  */
17307c478bd9Sstevel@tonic-gate static void
17317c478bd9Sstevel@tonic-gate target_activate_all(struct phyint_instance *pii)
17327c478bd9Sstevel@tonic-gate {
17337c478bd9Sstevel@tonic-gate 	struct target *tg;
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	assert(pii->pii_ntargets == 0);
17367c478bd9Sstevel@tonic-gate 	assert(pii->pii_target_next == NULL);
17377c478bd9Sstevel@tonic-gate 	assert(pii->pii_rtt_target_next == NULL);
17387c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets_are_routers);
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 	while (pii->pii_ntargets < MIN_PROBE_TARGETS) {
17417c478bd9Sstevel@tonic-gate 		tg = target_select_best(pii);
17427c478bd9Sstevel@tonic-gate 		if (tg == NULL) {
17437c478bd9Sstevel@tonic-gate 			/* We are out of targets */
17447c478bd9Sstevel@tonic-gate 			return;
17457c478bd9Sstevel@tonic-gate 		}
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
17487c478bd9Sstevel@tonic-gate 		assert(tg->tg_status != TG_ACTIVE);
17497c478bd9Sstevel@tonic-gate 		tg->tg_status = TG_ACTIVE;
17507c478bd9Sstevel@tonic-gate 		pii->pii_ntargets++;
17517c478bd9Sstevel@tonic-gate 		if (pii->pii_target_next == NULL) {
17527c478bd9Sstevel@tonic-gate 			pii->pii_target_next = tg;
17537c478bd9Sstevel@tonic-gate 			pii->pii_rtt_target_next = tg;
17547c478bd9Sstevel@tonic-gate 		}
17557c478bd9Sstevel@tonic-gate 	}
17567c478bd9Sstevel@tonic-gate }
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate static struct target *
17597c478bd9Sstevel@tonic-gate target_first(struct phyint_instance *pii)
17607c478bd9Sstevel@tonic-gate {
17617c478bd9Sstevel@tonic-gate 	struct target *tg;
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) {
17647c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
17657c478bd9Sstevel@tonic-gate 		if (tg->tg_status == TG_ACTIVE)
17667c478bd9Sstevel@tonic-gate 			break;
17677c478bd9Sstevel@tonic-gate 	}
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	return (tg);
17707c478bd9Sstevel@tonic-gate }
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate /*
17737c478bd9Sstevel@tonic-gate  * Create a default target entry.
17747c478bd9Sstevel@tonic-gate  */
17757c478bd9Sstevel@tonic-gate void
17767c478bd9Sstevel@tonic-gate target_create(struct phyint_instance *pii, struct in6_addr addr,
17777c478bd9Sstevel@tonic-gate     boolean_t is_router)
17787c478bd9Sstevel@tonic-gate {
17797c478bd9Sstevel@tonic-gate 	struct target *tg;
17807c478bd9Sstevel@tonic-gate 	struct phyint *pi;
17817c478bd9Sstevel@tonic-gate 	struct logint *li;
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET) {
17847c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 		logdebug("target_create(%s %s, %s)\n",
17877c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name,
17887c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, addr, abuf, sizeof (abuf)));
17897c478bd9Sstevel@tonic-gate 	}
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	/*
17927c478bd9Sstevel@tonic-gate 	 * If the test address is not yet initialized, do not add
17937c478bd9Sstevel@tonic-gate 	 * any target, since we cannot determine whether the target
17947c478bd9Sstevel@tonic-gate 	 * belongs to the same subnet as the test address.
17957c478bd9Sstevel@tonic-gate 	 */
17967c478bd9Sstevel@tonic-gate 	li = pii->pii_probe_logint;
17977c478bd9Sstevel@tonic-gate 	if (li == NULL)
17987c478bd9Sstevel@tonic-gate 		return;
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 	/*
18017c478bd9Sstevel@tonic-gate 	 * If there are multiple subnets associated with an interface, then
18027c478bd9Sstevel@tonic-gate 	 * add the target to this phyint instance, only if it belongs to the
18037c478bd9Sstevel@tonic-gate 	 * same subnet as the test address. The reason is that interface
18047c478bd9Sstevel@tonic-gate 	 * routes derived from non-test-addresses i.e. non-IFF_NOFAILOVER
18057c478bd9Sstevel@tonic-gate 	 * addresses, will disappear after failover, and the targets will not
18067c478bd9Sstevel@tonic-gate 	 * be reachable from this interface.
18077c478bd9Sstevel@tonic-gate 	 */
18087c478bd9Sstevel@tonic-gate 	if (!prefix_equal(li->li_subnet, addr, li->li_subnet_len))
18097c478bd9Sstevel@tonic-gate 		return;
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 	if (pii->pii_targets != NULL) {
18127c478bd9Sstevel@tonic-gate 		assert(pii->pii_ntargets <= MAX_PROBE_TARGETS);
18137c478bd9Sstevel@tonic-gate 		if (is_router) {
18147c478bd9Sstevel@tonic-gate 			if (!pii->pii_targets_are_routers) {
18157c478bd9Sstevel@tonic-gate 				/*
18167c478bd9Sstevel@tonic-gate 				 * Prefer router over hosts. Using hosts is a
18177c478bd9Sstevel@tonic-gate 				 * fallback mechanism, hence delete all host
18187c478bd9Sstevel@tonic-gate 				 * targets.
18197c478bd9Sstevel@tonic-gate 				 */
18207c478bd9Sstevel@tonic-gate 				while (pii->pii_targets != NULL)
18217c478bd9Sstevel@tonic-gate 					target_delete(pii->pii_targets);
18227c478bd9Sstevel@tonic-gate 			}
18237c478bd9Sstevel@tonic-gate 		} else {
18247c478bd9Sstevel@tonic-gate 			/*
18257c478bd9Sstevel@tonic-gate 			 * Routers take precedence over hosts. If this
18267c478bd9Sstevel@tonic-gate 			 * is a router list and we are trying to add a
18277c478bd9Sstevel@tonic-gate 			 * host, just return. If this is a host list
18287c478bd9Sstevel@tonic-gate 			 * and if we have sufficient targets, just return
18297c478bd9Sstevel@tonic-gate 			 */
18307c478bd9Sstevel@tonic-gate 			if (pii->pii_targets_are_routers ||
18317c478bd9Sstevel@tonic-gate 			    pii->pii_ntargets == MAX_PROBE_TARGETS)
18327c478bd9Sstevel@tonic-gate 				return;
18337c478bd9Sstevel@tonic-gate 		}
18347c478bd9Sstevel@tonic-gate 	}
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 	tg = calloc(1, sizeof (struct target));
18377c478bd9Sstevel@tonic-gate 	if (tg == NULL) {
18387c478bd9Sstevel@tonic-gate 		logperror("target_create: calloc");
18397c478bd9Sstevel@tonic-gate 		return;
18407c478bd9Sstevel@tonic-gate 	}
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	tg->tg_phyint_inst = pii;
18437c478bd9Sstevel@tonic-gate 	tg->tg_address = addr;
18447c478bd9Sstevel@tonic-gate 	tg->tg_in_use = 1;
18457c478bd9Sstevel@tonic-gate 	tg->tg_rtt_sa = -1;
18467c478bd9Sstevel@tonic-gate 	tg->tg_num_deferred = 0;
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 	/*
18497c478bd9Sstevel@tonic-gate 	 * If this is the first target, set 'pii_targets_are_routers'
18507c478bd9Sstevel@tonic-gate 	 * The list of targets is either a list of hosts or list or
18517c478bd9Sstevel@tonic-gate 	 * routers, but not a mix.
18527c478bd9Sstevel@tonic-gate 	 */
18537c478bd9Sstevel@tonic-gate 	if (pii->pii_targets == NULL) {
18547c478bd9Sstevel@tonic-gate 		assert(pii->pii_ntargets == 0);
18557c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next == NULL);
18567c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next == NULL);
18577c478bd9Sstevel@tonic-gate 		pii->pii_targets_are_routers = is_router ? 1 : 0;
18587c478bd9Sstevel@tonic-gate 	}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	if (pii->pii_ntargets == MAX_PROBE_TARGETS) {
18617c478bd9Sstevel@tonic-gate 		assert(pii->pii_targets_are_routers);
18627c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next != NULL);
18637c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next != NULL);
18647c478bd9Sstevel@tonic-gate 		tg->tg_status = TG_UNUSED;
18657c478bd9Sstevel@tonic-gate 	} else {
18667c478bd9Sstevel@tonic-gate 		if (pii->pii_ntargets == 0) {
18677c478bd9Sstevel@tonic-gate 			assert(pii->pii_target_next == NULL);
18687c478bd9Sstevel@tonic-gate 			pii->pii_target_next = tg;
18697c478bd9Sstevel@tonic-gate 			pii->pii_rtt_target_next = tg;
18707c478bd9Sstevel@tonic-gate 		}
18717c478bd9Sstevel@tonic-gate 		pii->pii_ntargets++;
18727c478bd9Sstevel@tonic-gate 		tg->tg_status = TG_ACTIVE;
18737c478bd9Sstevel@tonic-gate 	}
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	target_insert(pii, tg);
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	/*
1878*921e7e07Smeem 	 * Change state to PI_RUNNING if this phyint instance is capable of
1879*921e7e07Smeem 	 * sending and receiving probes -- that is, if we know of at least 1
1880*921e7e07Smeem 	 * target, and this phyint instance is probe-capable.  For more
1881*921e7e07Smeem 	 * details, see the phyint state diagram in mpd_probe.c.
18827c478bd9Sstevel@tonic-gate 	 */
18837c478bd9Sstevel@tonic-gate 	pi = pii->pii_phyint;
18847c478bd9Sstevel@tonic-gate 	if (pi->pi_state == PI_NOTARGETS && PROBE_CAPABLE(pii)) {
18857c478bd9Sstevel@tonic-gate 		if (pi->pi_flags & IFF_FAILED)
18867c478bd9Sstevel@tonic-gate 			phyint_chstate(pi, PI_FAILED);
18877c478bd9Sstevel@tonic-gate 		else
18887c478bd9Sstevel@tonic-gate 			phyint_chstate(pi, PI_RUNNING);
18897c478bd9Sstevel@tonic-gate 	}
18907c478bd9Sstevel@tonic-gate }
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate /*
18937c478bd9Sstevel@tonic-gate  * Add the target address named by `addr' to phyint instance `pii' if it does
18947c478bd9Sstevel@tonic-gate  * not already exist.  If the target is a router, `is_router' should be set to
18957c478bd9Sstevel@tonic-gate  * B_TRUE.
18967c478bd9Sstevel@tonic-gate  */
18977c478bd9Sstevel@tonic-gate void
18987c478bd9Sstevel@tonic-gate target_add(struct phyint_instance *pii, struct in6_addr addr,
18997c478bd9Sstevel@tonic-gate     boolean_t is_router)
19007c478bd9Sstevel@tonic-gate {
19017c478bd9Sstevel@tonic-gate 	struct target *tg;
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 	if (pii == NULL)
19047c478bd9Sstevel@tonic-gate 		return;
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	tg = target_lookup(pii, addr);
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	/*
19097c478bd9Sstevel@tonic-gate 	 * If the target does not exist, create it; target_create() will set
19107c478bd9Sstevel@tonic-gate 	 * tg_in_use to true.  If it exists already, and it is a router
19117c478bd9Sstevel@tonic-gate 	 * target, set tg_in_use to to true, so that init_router_targets()
19127c478bd9Sstevel@tonic-gate 	 * won't delete it
19137c478bd9Sstevel@tonic-gate 	 */
19147c478bd9Sstevel@tonic-gate 	if (tg == NULL)
19157c478bd9Sstevel@tonic-gate 		target_create(pii, addr, is_router);
19167c478bd9Sstevel@tonic-gate 	else if (is_router)
19177c478bd9Sstevel@tonic-gate 		tg->tg_in_use = 1;
19187c478bd9Sstevel@tonic-gate }
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate /*
19217c478bd9Sstevel@tonic-gate  * Insert target at head of linked list of targets for the associated
19227c478bd9Sstevel@tonic-gate  * phyint instance
19237c478bd9Sstevel@tonic-gate  */
19247c478bd9Sstevel@tonic-gate static void
19257c478bd9Sstevel@tonic-gate target_insert(struct phyint_instance *pii, struct target *tg)
19267c478bd9Sstevel@tonic-gate {
19277c478bd9Sstevel@tonic-gate 	tg->tg_next = pii->pii_targets;
19287c478bd9Sstevel@tonic-gate 	tg->tg_prev = NULL;
19297c478bd9Sstevel@tonic-gate 	if (tg->tg_next != NULL)
19307c478bd9Sstevel@tonic-gate 		tg->tg_next->tg_prev = tg;
19317c478bd9Sstevel@tonic-gate 	pii->pii_targets = tg;
19327c478bd9Sstevel@tonic-gate }
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate /*
19357c478bd9Sstevel@tonic-gate  * Delete a target (unlink and free).
19367c478bd9Sstevel@tonic-gate  */
19377c478bd9Sstevel@tonic-gate void
19387c478bd9Sstevel@tonic-gate target_delete(struct target *tg)
19397c478bd9Sstevel@tonic-gate {
19407c478bd9Sstevel@tonic-gate 	int af;
19417c478bd9Sstevel@tonic-gate 	struct phyint_instance	*pii;
19427c478bd9Sstevel@tonic-gate 	struct phyint_instance	*pii_other;
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	pii = tg->tg_phyint_inst;
19457c478bd9Sstevel@tonic-gate 	af = pii->pii_af;
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET) {
19487c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 		logdebug("target_delete(%s %s, %s)\n",
19517c478bd9Sstevel@tonic-gate 		    AF_STR(af), pii->pii_name,
19527c478bd9Sstevel@tonic-gate 		    pr_addr(af, tg->tg_address, abuf, sizeof (abuf)));
19537c478bd9Sstevel@tonic-gate 	}
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 	/*
19567c478bd9Sstevel@tonic-gate 	 * Target must be in the list of targets for this phyint
19577c478bd9Sstevel@tonic-gate 	 * instance.
19587c478bd9Sstevel@tonic-gate 	 */
19597c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets == tg || tg->tg_prev != NULL);
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	/*
19627c478bd9Sstevel@tonic-gate 	 * Reset all references to 'tg' in the probe information
19637c478bd9Sstevel@tonic-gate 	 * for this phyint.
19647c478bd9Sstevel@tonic-gate 	 */
19657c478bd9Sstevel@tonic-gate 	reset_pii_probes(pii, tg);
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	/*
19687c478bd9Sstevel@tonic-gate 	 * Remove this target from the list of targets of this
19697c478bd9Sstevel@tonic-gate 	 * phyint instance.
19707c478bd9Sstevel@tonic-gate 	 */
19717c478bd9Sstevel@tonic-gate 	if (tg->tg_prev == NULL) {
19727c478bd9Sstevel@tonic-gate 		pii->pii_targets = tg->tg_next;
19737c478bd9Sstevel@tonic-gate 	} else {
19747c478bd9Sstevel@tonic-gate 		tg->tg_prev->tg_next = tg->tg_next;
19757c478bd9Sstevel@tonic-gate 	}
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 	if (tg->tg_next != NULL)
19787c478bd9Sstevel@tonic-gate 		tg->tg_next->tg_prev = tg->tg_prev;
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 	tg->tg_next = NULL;
19817c478bd9Sstevel@tonic-gate 	tg->tg_prev = NULL;
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 	if (tg->tg_status == TG_ACTIVE)
19847c478bd9Sstevel@tonic-gate 		pii->pii_ntargets--;
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	/*
19877c478bd9Sstevel@tonic-gate 	 * Adjust the next target to probe, if it points to
19887c478bd9Sstevel@tonic-gate 	 * to the currently deleted target.
19897c478bd9Sstevel@tonic-gate 	 */
19907c478bd9Sstevel@tonic-gate 	if (pii->pii_target_next == tg)
19917c478bd9Sstevel@tonic-gate 		pii->pii_target_next = target_first(pii);
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 	if (pii->pii_rtt_target_next == tg)
19947c478bd9Sstevel@tonic-gate 		pii->pii_rtt_target_next = target_first(pii);
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 	free(tg);
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 	/*
19997c478bd9Sstevel@tonic-gate 	 * The number of active targets pii_ntargets == 0 iff
20007c478bd9Sstevel@tonic-gate 	 * the next active target pii->pii_target_next == NULL
20017c478bd9Sstevel@tonic-gate 	 */
20027c478bd9Sstevel@tonic-gate 	if (pii->pii_ntargets != 0) {
20037c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next != NULL);
20047c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next != NULL);
20057c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next->tg_status == TG_ACTIVE);
20067c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next->tg_status == TG_ACTIVE);
20077c478bd9Sstevel@tonic-gate 		return;
20087c478bd9Sstevel@tonic-gate 	}
20097c478bd9Sstevel@tonic-gate 
20107c478bd9Sstevel@tonic-gate 	/* At this point, we don't have any active targets. */
20117c478bd9Sstevel@tonic-gate 	assert(pii->pii_target_next == NULL);
20127c478bd9Sstevel@tonic-gate 	assert(pii->pii_rtt_target_next == NULL);
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 	if (pii->pii_targets_are_routers) {
20157c478bd9Sstevel@tonic-gate 		/*
20167c478bd9Sstevel@tonic-gate 		 * Activate any TG_SLOW or TG_DEAD router targets,
20177c478bd9Sstevel@tonic-gate 		 * since we don't have any other targets
20187c478bd9Sstevel@tonic-gate 		 */
20197c478bd9Sstevel@tonic-gate 		target_activate_all(pii);
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 		if (pii->pii_ntargets != 0) {
20227c478bd9Sstevel@tonic-gate 			assert(pii->pii_target_next != NULL);
20237c478bd9Sstevel@tonic-gate 			assert(pii->pii_rtt_target_next != NULL);
20247c478bd9Sstevel@tonic-gate 			assert(pii->pii_target_next->tg_status == TG_ACTIVE);
20257c478bd9Sstevel@tonic-gate 			assert(pii->pii_rtt_target_next->tg_status ==
20267c478bd9Sstevel@tonic-gate 			    TG_ACTIVE);
20277c478bd9Sstevel@tonic-gate 			return;
20287c478bd9Sstevel@tonic-gate 		}
20297c478bd9Sstevel@tonic-gate 	}
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate 	/*
20327c478bd9Sstevel@tonic-gate 	 * If we still don't have any active targets, the list must
20337c478bd9Sstevel@tonic-gate 	 * must be really empty. There aren't even TG_SLOW or TG_DEAD
20347c478bd9Sstevel@tonic-gate 	 * targets. Zero out the probe stats since it will not be
20357c478bd9Sstevel@tonic-gate 	 * relevant any longer.
20367c478bd9Sstevel@tonic-gate 	 */
20377c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets == NULL);
20387c478bd9Sstevel@tonic-gate 	clear_pii_probe_stats(pii);
20397c478bd9Sstevel@tonic-gate 	pii_other = phyint_inst_other(pii);
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate 	/*
20427c478bd9Sstevel@tonic-gate 	 * If there are no targets on both instances,
20437c478bd9Sstevel@tonic-gate 	 * go back to PI_NOTARGETS state, since we cannot
20447c478bd9Sstevel@tonic-gate 	 * probe this phyint any more. For more details,
20457c478bd9Sstevel@tonic-gate 	 * please see phyint state diagram in mpd_probe.c.
20467c478bd9Sstevel@tonic-gate 	 */
20477c478bd9Sstevel@tonic-gate 	if (!PROBE_CAPABLE(pii_other))
20487c478bd9Sstevel@tonic-gate 		phyint_chstate(pii->pii_phyint, PI_NOTARGETS);
20497c478bd9Sstevel@tonic-gate }
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate /*
20527c478bd9Sstevel@tonic-gate  * Flush the target list of every phyint in the group, if the list
20537c478bd9Sstevel@tonic-gate  * is a host target list. This is called if group failure is suspected.
20547c478bd9Sstevel@tonic-gate  * If all targets have failed, multicast will subsequently discover new
20557c478bd9Sstevel@tonic-gate  * targets. Else it is a group failure.
20567c478bd9Sstevel@tonic-gate  * Note: This function is a no-op if the list is a router target list.
20577c478bd9Sstevel@tonic-gate  */
20587c478bd9Sstevel@tonic-gate static void
20597c478bd9Sstevel@tonic-gate target_flush_hosts(struct phyint_group *pg)
20607c478bd9Sstevel@tonic-gate {
20617c478bd9Sstevel@tonic-gate 	struct phyint *pi;
20627c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET)
20657c478bd9Sstevel@tonic-gate 		logdebug("target_flush_hosts(%s)\n", pg->pg_name);
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext) {
20687c478bd9Sstevel@tonic-gate 		pii = pi->pi_v4;
20697c478bd9Sstevel@tonic-gate 		if (pii != NULL && !pii->pii_targets_are_routers) {
20707c478bd9Sstevel@tonic-gate 			/*
20717c478bd9Sstevel@tonic-gate 			 * Delete all the targets. When the list becomes
20727c478bd9Sstevel@tonic-gate 			 * empty, target_delete() will set pii->pii_targets
20737c478bd9Sstevel@tonic-gate 			 * to NULL.
20747c478bd9Sstevel@tonic-gate 			 */
20757c478bd9Sstevel@tonic-gate 			while (pii->pii_targets != NULL)
20767c478bd9Sstevel@tonic-gate 				target_delete(pii->pii_targets);
20777c478bd9Sstevel@tonic-gate 		}
20787c478bd9Sstevel@tonic-gate 		pii = pi->pi_v6;
20797c478bd9Sstevel@tonic-gate 		if (pii != NULL && !pii->pii_targets_are_routers) {
20807c478bd9Sstevel@tonic-gate 			/*
20817c478bd9Sstevel@tonic-gate 			 * Delete all the targets. When the list becomes
20827c478bd9Sstevel@tonic-gate 			 * empty, target_delete() will set pii->pii_targets
20837c478bd9Sstevel@tonic-gate 			 * to NULL.
20847c478bd9Sstevel@tonic-gate 			 */
20857c478bd9Sstevel@tonic-gate 			while (pii->pii_targets != NULL)
20867c478bd9Sstevel@tonic-gate 				target_delete(pii->pii_targets);
20877c478bd9Sstevel@tonic-gate 		}
20887c478bd9Sstevel@tonic-gate 	}
20897c478bd9Sstevel@tonic-gate }
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate /*
20927c478bd9Sstevel@tonic-gate  * Reset all references to 'target' in the probe info, as this target is
20937c478bd9Sstevel@tonic-gate  * being deleted. The pr_target field is guaranteed to be non-null if
20947c478bd9Sstevel@tonic-gate  * pr_status is PR_UNACKED. So we change the pr_status to PR_LOST, so that
20957c478bd9Sstevel@tonic-gate  * pr_target will not be accessed unconditionally.
20967c478bd9Sstevel@tonic-gate  */
20977c478bd9Sstevel@tonic-gate static void
20987c478bd9Sstevel@tonic-gate reset_pii_probes(struct phyint_instance *pii, struct target *tg)
20997c478bd9Sstevel@tonic-gate {
21007c478bd9Sstevel@tonic-gate 	int i;
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 	for (i = 0; i < PROBE_STATS_COUNT; i++) {
21037c478bd9Sstevel@tonic-gate 		if (pii->pii_probes[i].pr_target == tg) {
21047c478bd9Sstevel@tonic-gate 			pii->pii_probes[i].pr_target = NULL;
21057c478bd9Sstevel@tonic-gate 			if (pii->pii_probes[i].pr_status == PR_UNACKED)
21067c478bd9Sstevel@tonic-gate 				pii->pii_probes[i].pr_status = PR_LOST;
21077c478bd9Sstevel@tonic-gate 		}
21087c478bd9Sstevel@tonic-gate 	}
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate }
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate /*
21137c478bd9Sstevel@tonic-gate  * Clear the probe statistics array.
21147c478bd9Sstevel@tonic-gate  */
21157c478bd9Sstevel@tonic-gate void
21167c478bd9Sstevel@tonic-gate clear_pii_probe_stats(struct phyint_instance *pii)
21177c478bd9Sstevel@tonic-gate {
21187c478bd9Sstevel@tonic-gate 	bzero(pii->pii_probes, sizeof (struct probe_stats) * PROBE_STATS_COUNT);
21197c478bd9Sstevel@tonic-gate 	/* Reset the next probe index in the probe stats array */
21207c478bd9Sstevel@tonic-gate 	pii->pii_probe_next = 0;
21217c478bd9Sstevel@tonic-gate }
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate static void
21247c478bd9Sstevel@tonic-gate target_print(struct target *tg)
21257c478bd9Sstevel@tonic-gate {
21267c478bd9Sstevel@tonic-gate 	char	abuf[INET6_ADDRSTRLEN];
21277c478bd9Sstevel@tonic-gate 	char	buf[128];
21287c478bd9Sstevel@tonic-gate 	char	buf2[128];
21297c478bd9Sstevel@tonic-gate 	int	af;
21307c478bd9Sstevel@tonic-gate 	int	i;
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	af = tg->tg_phyint_inst->pii_af;
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 	logdebug("Target on %s %s addr %s\n"
21357c478bd9Sstevel@tonic-gate 	    "status %d rtt_sa %d rtt_sd %d crtt %d tg_in_use %d\n",
21367c478bd9Sstevel@tonic-gate 	    AF_STR(af), tg->tg_phyint_inst->pii_name,
21377c478bd9Sstevel@tonic-gate 	    pr_addr(af, tg->tg_address, abuf, sizeof (abuf)),
21387c478bd9Sstevel@tonic-gate 	    tg->tg_status, tg->tg_rtt_sa, tg->tg_rtt_sd,
21397c478bd9Sstevel@tonic-gate 	    tg->tg_crtt, tg->tg_in_use);
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate 	buf[0] = '\0';
21427c478bd9Sstevel@tonic-gate 	for (i = 0; i < tg->tg_num_deferred; i++) {
21437c478bd9Sstevel@tonic-gate 		(void) snprintf(buf2, sizeof (buf2), " %dms",
21447c478bd9Sstevel@tonic-gate 		    tg->tg_deferred[i]);
21457c478bd9Sstevel@tonic-gate 		(void) strlcat(buf, buf2, sizeof (buf));
21467c478bd9Sstevel@tonic-gate 	}
21477c478bd9Sstevel@tonic-gate 	logdebug("deferred rtts:%s\n", buf);
21487c478bd9Sstevel@tonic-gate }
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate void
21517c478bd9Sstevel@tonic-gate phyint_inst_print_all(void)
21527c478bd9Sstevel@tonic-gate {
21537c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
21547c478bd9Sstevel@tonic-gate 
21557c478bd9Sstevel@tonic-gate 	for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) {
21567c478bd9Sstevel@tonic-gate 		phyint_inst_print(pii);
21577c478bd9Sstevel@tonic-gate 	}
21587c478bd9Sstevel@tonic-gate }
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate /*
21617c478bd9Sstevel@tonic-gate  * Convert length for a mask to the mask.
21627c478bd9Sstevel@tonic-gate  */
21637c478bd9Sstevel@tonic-gate static void
21647c478bd9Sstevel@tonic-gate ip_index_to_mask_v6(uint_t masklen, struct in6_addr *bitmask)
21657c478bd9Sstevel@tonic-gate {
21667c478bd9Sstevel@tonic-gate 	int	j;
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	assert(masklen <= IPV6_ABITS);
21697c478bd9Sstevel@tonic-gate 	bzero((char *)bitmask, sizeof (*bitmask));
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate 	/* Make the 'masklen' leftmost bits one */
21727c478bd9Sstevel@tonic-gate 	for (j = 0; masklen > 8; masklen -= 8, j++)
21737c478bd9Sstevel@tonic-gate 		bitmask->s6_addr[j] = 0xff;
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	bitmask->s6_addr[j] = 0xff << (8 - masklen);
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate }
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate /*
21807c478bd9Sstevel@tonic-gate  * Compare two prefixes that have the same prefix length.
21817c478bd9Sstevel@tonic-gate  * Fails if the prefix length is unreasonable.
21827c478bd9Sstevel@tonic-gate  */
21837c478bd9Sstevel@tonic-gate static boolean_t
21847c478bd9Sstevel@tonic-gate prefix_equal(struct in6_addr p1, struct in6_addr p2, int prefix_len)
21857c478bd9Sstevel@tonic-gate {
21867c478bd9Sstevel@tonic-gate 	uchar_t mask;
21877c478bd9Sstevel@tonic-gate 	int j;
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 	if (prefix_len < 0 || prefix_len > IPV6_ABITS)
21907c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 	for (j = 0; prefix_len > 8; prefix_len -= 8, j++)
21937c478bd9Sstevel@tonic-gate 		if (p1.s6_addr[j] != p2.s6_addr[j])
21947c478bd9Sstevel@tonic-gate 			return (_B_FALSE);
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 	/* Make the N leftmost bits one */
21977c478bd9Sstevel@tonic-gate 	mask = 0xff << (8 - prefix_len);
21987c478bd9Sstevel@tonic-gate 	if ((p1.s6_addr[j] & mask) != (p2.s6_addr[j] & mask))
21997c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
22007c478bd9Sstevel@tonic-gate 
22017c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
22027c478bd9Sstevel@tonic-gate }
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate /*
22057c478bd9Sstevel@tonic-gate  * Get the number of UP logints (excluding IFF_NOFAILOVERs), on both
22067c478bd9Sstevel@tonic-gate  * IPv4 and IPv6 put together. The phyint with the least such number
22077c478bd9Sstevel@tonic-gate  * will be used as the failover destination, if no standby interface is
22087c478bd9Sstevel@tonic-gate  * available
22097c478bd9Sstevel@tonic-gate  */
22107c478bd9Sstevel@tonic-gate int
22117c478bd9Sstevel@tonic-gate logint_upcount(struct phyint *pi)
22127c478bd9Sstevel@tonic-gate {
22137c478bd9Sstevel@tonic-gate 	struct	logint	*li;
22147c478bd9Sstevel@tonic-gate 	struct	phyint_instance *pii;
22157c478bd9Sstevel@tonic-gate 	int count = 0;
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 	pii = pi->pi_v4;
22187c478bd9Sstevel@tonic-gate 	if (pii != NULL) {
22197c478bd9Sstevel@tonic-gate 		for (li = pii->pii_logint; li != NULL; li = li->li_next) {
22207c478bd9Sstevel@tonic-gate 			if ((li->li_flags &
22217c478bd9Sstevel@tonic-gate 			    (IFF_UP | IFF_NOFAILOVER)) == IFF_UP) {
22227c478bd9Sstevel@tonic-gate 				count++;
22237c478bd9Sstevel@tonic-gate 			}
22247c478bd9Sstevel@tonic-gate 		}
22257c478bd9Sstevel@tonic-gate 	}
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate 	pii = pi->pi_v6;
22287c478bd9Sstevel@tonic-gate 	if (pii != NULL) {
22297c478bd9Sstevel@tonic-gate 		for (li = pii->pii_logint; li != NULL; li = li->li_next) {
22307c478bd9Sstevel@tonic-gate 			if ((li->li_flags &
22317c478bd9Sstevel@tonic-gate 			    (IFF_UP | IFF_NOFAILOVER)) == IFF_UP) {
22327c478bd9Sstevel@tonic-gate 				count++;
22337c478bd9Sstevel@tonic-gate 			}
22347c478bd9Sstevel@tonic-gate 		}
22357c478bd9Sstevel@tonic-gate 	}
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 	return (count);
22387c478bd9Sstevel@tonic-gate }
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate /*
22417c478bd9Sstevel@tonic-gate  * Get the phyint instance with the other (IPv4 / IPv6) protocol
22427c478bd9Sstevel@tonic-gate  */
22437c478bd9Sstevel@tonic-gate struct phyint_instance *
22447c478bd9Sstevel@tonic-gate phyint_inst_other(struct phyint_instance *pii)
22457c478bd9Sstevel@tonic-gate {
22467c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET)
22477c478bd9Sstevel@tonic-gate 		return (pii->pii_phyint->pi_v6);
22487c478bd9Sstevel@tonic-gate 	else
22497c478bd9Sstevel@tonic-gate 		return (pii->pii_phyint->pi_v4);
22507c478bd9Sstevel@tonic-gate }
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate /*
22537c478bd9Sstevel@tonic-gate  * Post an EC_IPMP sysevent of subclass `subclass' and attributes `nvl'.
22547c478bd9Sstevel@tonic-gate  * Before sending the event, it prepends the current version of the IPMP
22557c478bd9Sstevel@tonic-gate  * sysevent API.  Returns 0 on success, -1 on failure (in either case,
22567c478bd9Sstevel@tonic-gate  * `nvl' is freed).
22577c478bd9Sstevel@tonic-gate  */
22587c478bd9Sstevel@tonic-gate static int
22597c478bd9Sstevel@tonic-gate post_event(const char *subclass, nvlist_t *nvl)
22607c478bd9Sstevel@tonic-gate {
22617c478bd9Sstevel@tonic-gate 	sysevent_id_t eid;
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_EVENT_VERSION,
22647c478bd9Sstevel@tonic-gate 	    IPMP_EVENT_CUR_VERSION);
22657c478bd9Sstevel@tonic-gate 	if (errno != 0) {
22667c478bd9Sstevel@tonic-gate 		logerr("cannot create `%s' event: %s", subclass,
22677c478bd9Sstevel@tonic-gate 		    strerror(errno));
22687c478bd9Sstevel@tonic-gate 		goto failed;
22697c478bd9Sstevel@tonic-gate 	}
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 	if (sysevent_post_event(EC_IPMP, (char *)subclass, SUNW_VENDOR,
22727c478bd9Sstevel@tonic-gate 	    "in.mpathd", nvl, &eid) == -1) {
22737c478bd9Sstevel@tonic-gate 		logerr("cannot send `%s' event: %s\n", subclass,
22747c478bd9Sstevel@tonic-gate 		    strerror(errno));
22757c478bd9Sstevel@tonic-gate 		goto failed;
22767c478bd9Sstevel@tonic-gate 	}
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
22797c478bd9Sstevel@tonic-gate 	return (0);
22807c478bd9Sstevel@tonic-gate failed:
22817c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
22827c478bd9Sstevel@tonic-gate 	return (-1);
22837c478bd9Sstevel@tonic-gate }
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate /*
22867c478bd9Sstevel@tonic-gate  * Return the external IPMP state associated with phyint `pi'.
22877c478bd9Sstevel@tonic-gate  */
22887c478bd9Sstevel@tonic-gate static ipmp_if_state_t
22897c478bd9Sstevel@tonic-gate ifstate(struct phyint *pi)
22907c478bd9Sstevel@tonic-gate {
22917c478bd9Sstevel@tonic-gate 	switch (pi->pi_state) {
22927c478bd9Sstevel@tonic-gate 	case PI_NOTARGETS:
22937c478bd9Sstevel@tonic-gate 		return (IPMP_IF_UNKNOWN);
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 	case PI_OFFLINE:
22967c478bd9Sstevel@tonic-gate 		return (IPMP_IF_OFFLINE);
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 	case PI_FAILED:
22997c478bd9Sstevel@tonic-gate 		return (IPMP_IF_FAILED);
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate 	case PI_RUNNING:
23027c478bd9Sstevel@tonic-gate 		return (IPMP_IF_OK);
23037c478bd9Sstevel@tonic-gate 	}
23047c478bd9Sstevel@tonic-gate 
23057c478bd9Sstevel@tonic-gate 	logerr("ifstate: unknown state %d; aborting\n", pi->pi_state);
23067c478bd9Sstevel@tonic-gate 	abort();
23077c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
23087c478bd9Sstevel@tonic-gate }
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate /*
23117c478bd9Sstevel@tonic-gate  * Return the external IPMP interface type associated with phyint `pi'.
23127c478bd9Sstevel@tonic-gate  */
23137c478bd9Sstevel@tonic-gate static ipmp_if_type_t
23147c478bd9Sstevel@tonic-gate iftype(struct phyint *pi)
23157c478bd9Sstevel@tonic-gate {
23167c478bd9Sstevel@tonic-gate 	if (pi->pi_flags & IFF_STANDBY)
23177c478bd9Sstevel@tonic-gate 		return (IPMP_IF_STANDBY);
23187c478bd9Sstevel@tonic-gate 	else
23197c478bd9Sstevel@tonic-gate 		return (IPMP_IF_NORMAL);
23207c478bd9Sstevel@tonic-gate }
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate /*
23237c478bd9Sstevel@tonic-gate  * Return the external IPMP group state associated with phyint group `pg'.
23247c478bd9Sstevel@tonic-gate  */
23257c478bd9Sstevel@tonic-gate static ipmp_group_state_t
23267c478bd9Sstevel@tonic-gate groupstate(struct phyint_group *pg)
23277c478bd9Sstevel@tonic-gate {
23287c478bd9Sstevel@tonic-gate 	return (GROUP_FAILED(pg) ? IPMP_GROUP_FAILED : IPMP_GROUP_OK);
23297c478bd9Sstevel@tonic-gate }
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate /*
23327c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_GROUP_STATE sysevent for phyint group `pg'.
23337c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
23347c478bd9Sstevel@tonic-gate  */
23357c478bd9Sstevel@tonic-gate static int
23367c478bd9Sstevel@tonic-gate phyint_group_state_event(struct phyint_group *pg)
23377c478bd9Sstevel@tonic-gate {
23387c478bd9Sstevel@tonic-gate 	nvlist_t	*nvl;
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
23417c478bd9Sstevel@tonic-gate 	if (errno != 0) {
23427c478bd9Sstevel@tonic-gate 		logperror("cannot create `group state change' event");
23437c478bd9Sstevel@tonic-gate 		return (-1);
23447c478bd9Sstevel@tonic-gate 	}
23457c478bd9Sstevel@tonic-gate 
23467c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
23477c478bd9Sstevel@tonic-gate 	if (errno != 0)
23487c478bd9Sstevel@tonic-gate 		goto failed;
23497c478bd9Sstevel@tonic-gate 
23507c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
23517c478bd9Sstevel@tonic-gate 	if (errno != 0)
23527c478bd9Sstevel@tonic-gate 		goto failed;
23537c478bd9Sstevel@tonic-gate 
23547c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_GROUP_STATE, groupstate(pg));
23557c478bd9Sstevel@tonic-gate 	if (errno != 0)
23567c478bd9Sstevel@tonic-gate 		goto failed;
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_GROUP_STATE, nvl));
23597c478bd9Sstevel@tonic-gate failed:
23607c478bd9Sstevel@tonic-gate 	logperror("cannot create `group state change' event");
23617c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
23627c478bd9Sstevel@tonic-gate 	return (-1);
23637c478bd9Sstevel@tonic-gate }
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate /*
23667c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_GROUP_CHANGE sysevent of type `op' for phyint group
23677c478bd9Sstevel@tonic-gate  * `pg'.  Returns 0 on success, -1 on failure.
23687c478bd9Sstevel@tonic-gate  */
23697c478bd9Sstevel@tonic-gate static int
23707c478bd9Sstevel@tonic-gate phyint_group_change_event(struct phyint_group *pg, ipmp_group_op_t op)
23717c478bd9Sstevel@tonic-gate {
23727c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
23757c478bd9Sstevel@tonic-gate 	if (errno != 0) {
23767c478bd9Sstevel@tonic-gate 		logperror("cannot create `group change' event");
23777c478bd9Sstevel@tonic-gate 		return (-1);
23787c478bd9Sstevel@tonic-gate 	}
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
23817c478bd9Sstevel@tonic-gate 	if (errno != 0)
23827c478bd9Sstevel@tonic-gate 		goto failed;
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
23857c478bd9Sstevel@tonic-gate 	if (errno != 0)
23867c478bd9Sstevel@tonic-gate 		goto failed;
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUPLIST_SIGNATURE,
23897c478bd9Sstevel@tonic-gate 	    phyint_grouplistsig);
23907c478bd9Sstevel@tonic-gate 	if (errno != 0)
23917c478bd9Sstevel@tonic-gate 		goto failed;
23927c478bd9Sstevel@tonic-gate 
23937c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_GROUP_OPERATION, op);
23947c478bd9Sstevel@tonic-gate 	if (errno != 0)
23957c478bd9Sstevel@tonic-gate 		goto failed;
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_GROUP_CHANGE, nvl));
23987c478bd9Sstevel@tonic-gate failed:
23997c478bd9Sstevel@tonic-gate 	logperror("cannot create `group change' event");
24007c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
24017c478bd9Sstevel@tonic-gate 	return (-1);
24027c478bd9Sstevel@tonic-gate }
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate /*
24057c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_GROUP_MEMBER_CHANGE sysevent for phyint `pi' in
24067c478bd9Sstevel@tonic-gate  * group `pg'.	Returns 0 on success, -1 on failure.
24077c478bd9Sstevel@tonic-gate  */
24087c478bd9Sstevel@tonic-gate static int
24097c478bd9Sstevel@tonic-gate phyint_group_member_event(struct phyint_group *pg, struct phyint *pi,
24107c478bd9Sstevel@tonic-gate     ipmp_if_op_t op)
24117c478bd9Sstevel@tonic-gate {
24127c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
24157c478bd9Sstevel@tonic-gate 	if (errno != 0) {
24167c478bd9Sstevel@tonic-gate 		logperror("cannot create `group member change' event");
24177c478bd9Sstevel@tonic-gate 		return (-1);
24187c478bd9Sstevel@tonic-gate 	}
24197c478bd9Sstevel@tonic-gate 
24207c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
24217c478bd9Sstevel@tonic-gate 	if (errno != 0)
24227c478bd9Sstevel@tonic-gate 		goto failed;
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
24257c478bd9Sstevel@tonic-gate 	if (errno != 0)
24267c478bd9Sstevel@tonic-gate 		goto failed;
24277c478bd9Sstevel@tonic-gate 
24287c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_OPERATION, op);
24297c478bd9Sstevel@tonic-gate 	if (errno != 0)
24307c478bd9Sstevel@tonic-gate 		goto failed;
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_IF_NAME, pi->pi_name);
24337c478bd9Sstevel@tonic-gate 	if (errno != 0)
24347c478bd9Sstevel@tonic-gate 		goto failed;
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_TYPE, iftype(pi));
24377c478bd9Sstevel@tonic-gate 	if (errno != 0)
24387c478bd9Sstevel@tonic-gate 		goto failed;
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_STATE, ifstate(pi));
24417c478bd9Sstevel@tonic-gate 	if (errno != 0)
24427c478bd9Sstevel@tonic-gate 		goto failed;
24437c478bd9Sstevel@tonic-gate 
24447c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_GROUP_MEMBER_CHANGE, nvl));
24457c478bd9Sstevel@tonic-gate failed:
24467c478bd9Sstevel@tonic-gate 	logperror("cannot create `group member change' event");
24477c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
24487c478bd9Sstevel@tonic-gate 	return (-1);
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate }
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate /*
24537c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_IF_CHANGE sysevent for phyint `pi' in group `pg'.
24547c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
24557c478bd9Sstevel@tonic-gate  */
24567c478bd9Sstevel@tonic-gate static int
24577c478bd9Sstevel@tonic-gate phyint_state_event(struct phyint_group *pg, struct phyint *pi)
24587c478bd9Sstevel@tonic-gate {
24597c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
24627c478bd9Sstevel@tonic-gate 	if (errno != 0) {
24637c478bd9Sstevel@tonic-gate 		logperror("cannot create `interface change' event");
24647c478bd9Sstevel@tonic-gate 		return (-1);
24657c478bd9Sstevel@tonic-gate 	}
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
24687c478bd9Sstevel@tonic-gate 	if (errno != 0)
24697c478bd9Sstevel@tonic-gate 		goto failed;
24707c478bd9Sstevel@tonic-gate 
24717c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
24727c478bd9Sstevel@tonic-gate 	if (errno != 0)
24737c478bd9Sstevel@tonic-gate 		goto failed;
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_IF_NAME, pi->pi_name);
24767c478bd9Sstevel@tonic-gate 	if (errno != 0)
24777c478bd9Sstevel@tonic-gate 		goto failed;
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_TYPE, iftype(pi));
24807c478bd9Sstevel@tonic-gate 	if (errno != 0)
24817c478bd9Sstevel@tonic-gate 		goto failed;
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_STATE, ifstate(pi));
24847c478bd9Sstevel@tonic-gate 	if (errno != 0)
24857c478bd9Sstevel@tonic-gate 		goto failed;
24867c478bd9Sstevel@tonic-gate 
24877c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_IF_CHANGE, nvl));
24887c478bd9Sstevel@tonic-gate failed:
24897c478bd9Sstevel@tonic-gate 	logperror("cannot create `interface change' event");
24907c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
24917c478bd9Sstevel@tonic-gate 	return (-1);
24927c478bd9Sstevel@tonic-gate 
24937c478bd9Sstevel@tonic-gate }
24947c478bd9Sstevel@tonic-gate 
24957c478bd9Sstevel@tonic-gate /*
24967c478bd9Sstevel@tonic-gate  * Generate a signature for use.  The signature is conceptually divided
24977c478bd9Sstevel@tonic-gate  * into two pieces: a random 16-bit "generation number" and a 48-bit
24987c478bd9Sstevel@tonic-gate  * monotonically increasing integer.  The generation number protects
24997c478bd9Sstevel@tonic-gate  * against stale updates to entities (e.g., IPMP groups) that have been
25007c478bd9Sstevel@tonic-gate  * deleted and since recreated.
25017c478bd9Sstevel@tonic-gate  */
25027c478bd9Sstevel@tonic-gate static uint64_t
25037c478bd9Sstevel@tonic-gate gensig(void)
25047c478bd9Sstevel@tonic-gate {
25057c478bd9Sstevel@tonic-gate 	static int seeded = 0;
25067c478bd9Sstevel@tonic-gate 
25077c478bd9Sstevel@tonic-gate 	if (seeded == 0) {
25087c478bd9Sstevel@tonic-gate 		srand48((long)gethrtime());
25097c478bd9Sstevel@tonic-gate 		seeded++;
25107c478bd9Sstevel@tonic-gate 	}
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate 	return ((uint64_t)lrand48() << 48 | 1);
25137c478bd9Sstevel@tonic-gate }
25147c478bd9Sstevel@tonic-gate 
25157c478bd9Sstevel@tonic-gate /*
25167c478bd9Sstevel@tonic-gate  * Store the information associated with group `grname' into a dynamically
25177c478bd9Sstevel@tonic-gate  * allocated structure pointed to by `*grinfopp'.  Returns an IPMP error code.
25187c478bd9Sstevel@tonic-gate  */
25197c478bd9Sstevel@tonic-gate unsigned int
25207c478bd9Sstevel@tonic-gate getgroupinfo(const char *grname, ipmp_groupinfo_t **grinfopp)
25217c478bd9Sstevel@tonic-gate {
25227c478bd9Sstevel@tonic-gate 	struct phyint_group	*pg;
25237c478bd9Sstevel@tonic-gate 	struct phyint		*pi;
25247c478bd9Sstevel@tonic-gate 	char			(*ifs)[LIFNAMSIZ];
25257c478bd9Sstevel@tonic-gate 	unsigned int		nif, i;
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 	pg = phyint_group_lookup(grname);
25287c478bd9Sstevel@tonic-gate 	if (pg == NULL)
25297c478bd9Sstevel@tonic-gate 		return (IPMP_EUNKGROUP);
25307c478bd9Sstevel@tonic-gate 
25317c478bd9Sstevel@tonic-gate 	/*
25327c478bd9Sstevel@tonic-gate 	 * Tally up the number of interfaces, allocate an array to hold them,
25337c478bd9Sstevel@tonic-gate 	 * and insert their names into the array.
25347c478bd9Sstevel@tonic-gate 	 */
25357c478bd9Sstevel@tonic-gate 	for (nif = 0, pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext)
25367c478bd9Sstevel@tonic-gate 		nif++;
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 	ifs = alloca(nif * sizeof (*ifs));
25397c478bd9Sstevel@tonic-gate 	for (i = 0, pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext, i++) {
25407c478bd9Sstevel@tonic-gate 		assert(i < nif);
25417c478bd9Sstevel@tonic-gate 		(void) strlcpy(ifs[i], pi->pi_name, LIFNAMSIZ);
25427c478bd9Sstevel@tonic-gate 	}
25437c478bd9Sstevel@tonic-gate 	assert(i == nif);
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate 	*grinfopp = ipmp_groupinfo_create(pg->pg_name, pg->pg_sig,
25467c478bd9Sstevel@tonic-gate 	    groupstate(pg), nif, ifs);
25477c478bd9Sstevel@tonic-gate 	return (*grinfopp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
25487c478bd9Sstevel@tonic-gate }
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate /*
25517c478bd9Sstevel@tonic-gate  * Store the information associated with interface `ifname' into a dynamically
25527c478bd9Sstevel@tonic-gate  * allocated structure pointed to by `*ifinfopp'.  Returns an IPMP error code.
25537c478bd9Sstevel@tonic-gate  */
25547c478bd9Sstevel@tonic-gate unsigned int
25557c478bd9Sstevel@tonic-gate getifinfo(const char *ifname, ipmp_ifinfo_t **ifinfopp)
25567c478bd9Sstevel@tonic-gate {
25577c478bd9Sstevel@tonic-gate 	struct phyint	*pi;
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate 	pi = phyint_lookup(ifname);
25607c478bd9Sstevel@tonic-gate 	if (pi == NULL)
25617c478bd9Sstevel@tonic-gate 		return (IPMP_EUNKIF);
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 	*ifinfopp = ipmp_ifinfo_create(pi->pi_name, pi->pi_group->pg_name,
25647c478bd9Sstevel@tonic-gate 	    ifstate(pi), iftype(pi));
25657c478bd9Sstevel@tonic-gate 	return (*ifinfopp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
25667c478bd9Sstevel@tonic-gate }
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate /*
25697c478bd9Sstevel@tonic-gate  * Store the current list of IPMP groups into a dynamically allocated
25707c478bd9Sstevel@tonic-gate  * structure pointed to by `*grlistpp'.	 Returns an IPMP error code.
25717c478bd9Sstevel@tonic-gate  */
25727c478bd9Sstevel@tonic-gate unsigned int
25737c478bd9Sstevel@tonic-gate getgrouplist(ipmp_grouplist_t **grlistpp)
25747c478bd9Sstevel@tonic-gate {
25757c478bd9Sstevel@tonic-gate 	struct phyint_group	*pg;
25767c478bd9Sstevel@tonic-gate 	char			(*groups)[LIFGRNAMSIZ];
25777c478bd9Sstevel@tonic-gate 	unsigned int		i, ngroup;
25787c478bd9Sstevel@tonic-gate 
25797c478bd9Sstevel@tonic-gate 	/*
25807c478bd9Sstevel@tonic-gate 	 * Tally up the number of groups, allocate an array to hold them, and
25817c478bd9Sstevel@tonic-gate 	 * insert their names into the array.
25827c478bd9Sstevel@tonic-gate 	 */
25837c478bd9Sstevel@tonic-gate 	for (ngroup = 0, pg = phyint_groups; pg != NULL; pg = pg->pg_next)
25847c478bd9Sstevel@tonic-gate 		ngroup++;
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 	groups = alloca(ngroup * sizeof (*groups));
25877c478bd9Sstevel@tonic-gate 	for (i = 0, pg = phyint_groups; pg != NULL; pg = pg->pg_next, i++) {
25887c478bd9Sstevel@tonic-gate 		assert(i < ngroup);
25897c478bd9Sstevel@tonic-gate 		(void) strlcpy(groups[i], pg->pg_name, LIFGRNAMSIZ);
25907c478bd9Sstevel@tonic-gate 	}
25917c478bd9Sstevel@tonic-gate 	assert(i == ngroup);
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate 	*grlistpp = ipmp_grouplist_create(phyint_grouplistsig, ngroup, groups);
25947c478bd9Sstevel@tonic-gate 	return (*grlistpp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
25957c478bd9Sstevel@tonic-gate }
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate /*
25987c478bd9Sstevel@tonic-gate  * Store a snapshot of the IPMP subsystem into a dynamically allocated
25997c478bd9Sstevel@tonic-gate  * structure pointed to by `*snapp'.  Returns an IPMP error code.
26007c478bd9Sstevel@tonic-gate  */
26017c478bd9Sstevel@tonic-gate unsigned int
26027c478bd9Sstevel@tonic-gate getsnap(ipmp_snap_t **snapp)
26037c478bd9Sstevel@tonic-gate {
26047c478bd9Sstevel@tonic-gate 	ipmp_grouplist_t	*grlistp;
26057c478bd9Sstevel@tonic-gate 	ipmp_groupinfo_t	*grinfop;
26067c478bd9Sstevel@tonic-gate 	ipmp_ifinfo_t		*ifinfop;
26077c478bd9Sstevel@tonic-gate 	ipmp_snap_t		*snap;
26087c478bd9Sstevel@tonic-gate 	struct phyint		*pi;
26097c478bd9Sstevel@tonic-gate 	unsigned int		i;
26107c478bd9Sstevel@tonic-gate 	int			retval;
26117c478bd9Sstevel@tonic-gate 
26127c478bd9Sstevel@tonic-gate 	snap = ipmp_snap_create();
26137c478bd9Sstevel@tonic-gate 	if (snap == NULL)
26147c478bd9Sstevel@tonic-gate 		return (IPMP_ENOMEM);
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 	/*
26177c478bd9Sstevel@tonic-gate 	 * Add group list.
26187c478bd9Sstevel@tonic-gate 	 */
26197c478bd9Sstevel@tonic-gate 	retval = getgrouplist(&snap->sn_grlistp);
26207c478bd9Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS) {
26217c478bd9Sstevel@tonic-gate 		ipmp_snap_free(snap);
26227c478bd9Sstevel@tonic-gate 		return (retval);
26237c478bd9Sstevel@tonic-gate 	}
26247c478bd9Sstevel@tonic-gate 
26257c478bd9Sstevel@tonic-gate 	/*
26267c478bd9Sstevel@tonic-gate 	 * Add information for each group in the list.
26277c478bd9Sstevel@tonic-gate 	 */
26287c478bd9Sstevel@tonic-gate 	grlistp = snap->sn_grlistp;
26297c478bd9Sstevel@tonic-gate 	for (i = 0; i < grlistp->gl_ngroup; i++) {
26307c478bd9Sstevel@tonic-gate 		retval = getgroupinfo(grlistp->gl_groups[i], &grinfop);
26317c478bd9Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
26327c478bd9Sstevel@tonic-gate 			ipmp_snap_free(snap);
26337c478bd9Sstevel@tonic-gate 			return (retval);
26347c478bd9Sstevel@tonic-gate 		}
26357c478bd9Sstevel@tonic-gate 		retval = ipmp_snap_addgroupinfo(snap, grinfop);
26367c478bd9Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
26377c478bd9Sstevel@tonic-gate 			ipmp_freegroupinfo(grinfop);
26387c478bd9Sstevel@tonic-gate 			ipmp_snap_free(snap);
26397c478bd9Sstevel@tonic-gate 			return (retval);
26407c478bd9Sstevel@tonic-gate 		}
26417c478bd9Sstevel@tonic-gate 	}
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 	/*
26447c478bd9Sstevel@tonic-gate 	 * Add information for each configured phyint.
26457c478bd9Sstevel@tonic-gate 	 */
26467c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
26477c478bd9Sstevel@tonic-gate 		retval = getifinfo(pi->pi_name, &ifinfop);
26487c478bd9Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
26497c478bd9Sstevel@tonic-gate 			ipmp_snap_free(snap);
26507c478bd9Sstevel@tonic-gate 			return (retval);
26517c478bd9Sstevel@tonic-gate 		}
26527c478bd9Sstevel@tonic-gate 		retval = ipmp_snap_addifinfo(snap, ifinfop);
26537c478bd9Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
26547c478bd9Sstevel@tonic-gate 			ipmp_freeifinfo(ifinfop);
26557c478bd9Sstevel@tonic-gate 			ipmp_snap_free(snap);
26567c478bd9Sstevel@tonic-gate 			return (retval);
26577c478bd9Sstevel@tonic-gate 		}
26587c478bd9Sstevel@tonic-gate 	}
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	*snapp = snap;
26617c478bd9Sstevel@tonic-gate 	return (IPMP_SUCCESS);
26627c478bd9Sstevel@tonic-gate }
2663