1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include "mpd_defs.h"
30*7c478bd9Sstevel@tonic-gate #include "mpd_tables.h"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate /*
33*7c478bd9Sstevel@tonic-gate  * Global list of phyints, phyint instances, phyint groups and the anonymous
34*7c478bd9Sstevel@tonic-gate  * group; the latter is initialized in phyint_init().
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate struct phyint *phyints = NULL;
37*7c478bd9Sstevel@tonic-gate struct phyint_instance	*phyint_instances = NULL;
38*7c478bd9Sstevel@tonic-gate struct phyint_group *phyint_groups = NULL;
39*7c478bd9Sstevel@tonic-gate struct phyint_group *phyint_anongroup;
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate /*
42*7c478bd9Sstevel@tonic-gate  * Grouplist signature; initialized in phyint_init().
43*7c478bd9Sstevel@tonic-gate  */
44*7c478bd9Sstevel@tonic-gate static uint64_t phyint_grouplistsig;
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate static void phyint_inst_insert(struct phyint_instance *pii);
47*7c478bd9Sstevel@tonic-gate static void phyint_inst_print(struct phyint_instance *pii);
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate static void phyint_insert(struct phyint *pi, struct phyint_group *pg);
50*7c478bd9Sstevel@tonic-gate static void phyint_delete(struct phyint *pi);
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate static void phyint_group_insert(struct phyint_group *pg);
53*7c478bd9Sstevel@tonic-gate static void phyint_group_delete(struct phyint_group *pg);
54*7c478bd9Sstevel@tonic-gate static struct phyint_group *phyint_group_lookup(const char *pg_name);
55*7c478bd9Sstevel@tonic-gate static struct phyint_group *phyint_group_create(const char *pg_name);
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate static void logint_print(struct logint *li);
58*7c478bd9Sstevel@tonic-gate static void logint_insert(struct phyint_instance *pii, struct logint *li);
59*7c478bd9Sstevel@tonic-gate static struct logint *logint_lookup(struct phyint_instance *pii, char *li_name);
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate static void target_print(struct target *tg);
62*7c478bd9Sstevel@tonic-gate static void target_insert(struct phyint_instance *pii, struct target *tg);
63*7c478bd9Sstevel@tonic-gate static struct target *target_first(struct phyint_instance *pii);
64*7c478bd9Sstevel@tonic-gate static struct target *target_select_best(struct phyint_instance *pii);
65*7c478bd9Sstevel@tonic-gate static void target_flush_hosts(struct phyint_group *pg);
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate static void reset_pii_probes(struct phyint_instance *pii, struct target *tg);
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate static boolean_t phyint_inst_v6_sockinit(struct phyint_instance *pii);
70*7c478bd9Sstevel@tonic-gate static boolean_t phyint_inst_v4_sockinit(struct phyint_instance *pii);
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate static void ip_index_to_mask_v6(uint_t masklen, struct in6_addr *bitmask);
73*7c478bd9Sstevel@tonic-gate static boolean_t prefix_equal(struct in6_addr p1, struct in6_addr p2,
74*7c478bd9Sstevel@tonic-gate     int prefix_len);
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate static int phyint_state_event(struct phyint_group *pg, struct phyint *pi);
77*7c478bd9Sstevel@tonic-gate static int phyint_group_state_event(struct phyint_group *pg);
78*7c478bd9Sstevel@tonic-gate static int phyint_group_change_event(struct phyint_group *pg, ipmp_group_op_t);
79*7c478bd9Sstevel@tonic-gate static int phyint_group_member_event(struct phyint_group *pg, struct phyint *pi,
80*7c478bd9Sstevel@tonic-gate     ipmp_if_op_t op);
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate static uint64_t gensig(void);
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /* Initialize any per-file global state.  Returns 0 on success, -1 on failure */
85*7c478bd9Sstevel@tonic-gate int
86*7c478bd9Sstevel@tonic-gate phyint_init(void)
87*7c478bd9Sstevel@tonic-gate {
88*7c478bd9Sstevel@tonic-gate 	phyint_grouplistsig = gensig();
89*7c478bd9Sstevel@tonic-gate 	if (track_all_phyints) {
90*7c478bd9Sstevel@tonic-gate 		phyint_anongroup = phyint_group_create("");
91*7c478bd9Sstevel@tonic-gate 		if (phyint_anongroup == NULL)
92*7c478bd9Sstevel@tonic-gate 			return (-1);
93*7c478bd9Sstevel@tonic-gate 		phyint_group_insert(phyint_anongroup);
94*7c478bd9Sstevel@tonic-gate 	}
95*7c478bd9Sstevel@tonic-gate 	return (0);
96*7c478bd9Sstevel@tonic-gate }
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate /* Return the phyint with the given name */
99*7c478bd9Sstevel@tonic-gate struct phyint *
100*7c478bd9Sstevel@tonic-gate phyint_lookup(const char *name)
101*7c478bd9Sstevel@tonic-gate {
102*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
105*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_lookup(%s)\n", name);
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
108*7c478bd9Sstevel@tonic-gate 		if (strncmp(pi->pi_name, name, sizeof (pi->pi_name)) == 0)
109*7c478bd9Sstevel@tonic-gate 			break;
110*7c478bd9Sstevel@tonic-gate 	}
111*7c478bd9Sstevel@tonic-gate 	return (pi);
112*7c478bd9Sstevel@tonic-gate }
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate /* Return the phyint instance with the given name and the given family */
115*7c478bd9Sstevel@tonic-gate struct phyint_instance *
116*7c478bd9Sstevel@tonic-gate phyint_inst_lookup(int af, char *name)
117*7c478bd9Sstevel@tonic-gate {
118*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
121*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_lookup(%s %s)\n", AF_STR(af), name);
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	assert(af == AF_INET || af == AF_INET6);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	pi = phyint_lookup(name);
126*7c478bd9Sstevel@tonic-gate 	if (pi == NULL)
127*7c478bd9Sstevel@tonic-gate 		return (NULL);
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 	return (PHYINT_INSTANCE(pi, af));
130*7c478bd9Sstevel@tonic-gate }
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate static struct phyint_group *
133*7c478bd9Sstevel@tonic-gate phyint_group_lookup(const char *pg_name)
134*7c478bd9Sstevel@tonic-gate {
135*7c478bd9Sstevel@tonic-gate 	struct phyint_group *pg;
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
138*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_group_lookup(%s)\n", pg_name);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	for (pg = phyint_groups; pg != NULL; pg = pg->pg_next) {
141*7c478bd9Sstevel@tonic-gate 		if (strncmp(pg->pg_name, pg_name, sizeof (pg->pg_name)) == 0)
142*7c478bd9Sstevel@tonic-gate 			break;
143*7c478bd9Sstevel@tonic-gate 	}
144*7c478bd9Sstevel@tonic-gate 	return (pg);
145*7c478bd9Sstevel@tonic-gate }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /*
148*7c478bd9Sstevel@tonic-gate  * Insert the phyint in the linked list of all phyints. If the phyint belongs
149*7c478bd9Sstevel@tonic-gate  * to some group, insert it in the phyint group list.
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate static void
152*7c478bd9Sstevel@tonic-gate phyint_insert(struct phyint *pi, struct phyint_group *pg)
153*7c478bd9Sstevel@tonic-gate {
154*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
155*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_insert(%s '%s')\n", pi->pi_name, pg->pg_name);
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	/* Insert the phyint at the head of the 'all phyints' list */
158*7c478bd9Sstevel@tonic-gate 	pi->pi_next = phyints;
159*7c478bd9Sstevel@tonic-gate 	pi->pi_prev = NULL;
160*7c478bd9Sstevel@tonic-gate 	if (phyints != NULL)
161*7c478bd9Sstevel@tonic-gate 		phyints->pi_prev = pi;
162*7c478bd9Sstevel@tonic-gate 	phyints = pi;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	/*
165*7c478bd9Sstevel@tonic-gate 	 * Insert the phyint at the head of the 'phyint_group members' list
166*7c478bd9Sstevel@tonic-gate 	 * of the phyint group to which it belongs.
167*7c478bd9Sstevel@tonic-gate 	 */
168*7c478bd9Sstevel@tonic-gate 	pi->pi_pgnext = NULL;
169*7c478bd9Sstevel@tonic-gate 	pi->pi_pgprev = NULL;
170*7c478bd9Sstevel@tonic-gate 	pi->pi_group = pg;
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	pi->pi_pgnext = pg->pg_phyint;
173*7c478bd9Sstevel@tonic-gate 	if (pi->pi_pgnext != NULL)
174*7c478bd9Sstevel@tonic-gate 		pi->pi_pgnext->pi_pgprev = pi;
175*7c478bd9Sstevel@tonic-gate 	pg->pg_phyint = pi;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	pg->pg_sig++;
178*7c478bd9Sstevel@tonic-gate 	(void) phyint_group_member_event(pg, pi, IPMP_IF_ADD);
179*7c478bd9Sstevel@tonic-gate }
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate /* Insert the phyint instance in the linked list of all phyint instances. */
182*7c478bd9Sstevel@tonic-gate static void
183*7c478bd9Sstevel@tonic-gate phyint_inst_insert(struct phyint_instance *pii)
184*7c478bd9Sstevel@tonic-gate {
185*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
186*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_insert(%s %s)\n",
187*7c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name);
188*7c478bd9Sstevel@tonic-gate 	}
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	/*
191*7c478bd9Sstevel@tonic-gate 	 * Insert the phyint at the head of the 'all phyint instances' list.
192*7c478bd9Sstevel@tonic-gate 	 */
193*7c478bd9Sstevel@tonic-gate 	pii->pii_next = phyint_instances;
194*7c478bd9Sstevel@tonic-gate 	pii->pii_prev = NULL;
195*7c478bd9Sstevel@tonic-gate 	if (phyint_instances != NULL)
196*7c478bd9Sstevel@tonic-gate 		phyint_instances->pii_prev = pii;
197*7c478bd9Sstevel@tonic-gate 	phyint_instances = pii;
198*7c478bd9Sstevel@tonic-gate }
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate /*
201*7c478bd9Sstevel@tonic-gate  * Create a new phyint with the given parameters. Also insert it into
202*7c478bd9Sstevel@tonic-gate  * the list of all phyints and the list of phyint group members by calling
203*7c478bd9Sstevel@tonic-gate  * phyint_insert().
204*7c478bd9Sstevel@tonic-gate  */
205*7c478bd9Sstevel@tonic-gate static struct phyint *
206*7c478bd9Sstevel@tonic-gate phyint_create(char *pi_name, struct phyint_group *pg, uint_t ifindex,
207*7c478bd9Sstevel@tonic-gate     uint64_t flags)
208*7c478bd9Sstevel@tonic-gate {
209*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	pi = calloc(1, sizeof (struct phyint));
212*7c478bd9Sstevel@tonic-gate 	if (pi == NULL) {
213*7c478bd9Sstevel@tonic-gate 		logperror("phyint_create: calloc");
214*7c478bd9Sstevel@tonic-gate 		return (NULL);
215*7c478bd9Sstevel@tonic-gate 	}
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	/*
218*7c478bd9Sstevel@tonic-gate 	 * Record the phyint values. Also insert the phyint into the
219*7c478bd9Sstevel@tonic-gate 	 * phyint group by calling phyint_insert().
220*7c478bd9Sstevel@tonic-gate 	 */
221*7c478bd9Sstevel@tonic-gate 	(void) strncpy(pi->pi_name, pi_name, sizeof (pi->pi_name));
222*7c478bd9Sstevel@tonic-gate 	pi->pi_name[sizeof (pi->pi_name) - 1] = '\0';
223*7c478bd9Sstevel@tonic-gate 	pi->pi_ifindex = ifindex;
224*7c478bd9Sstevel@tonic-gate 	pi->pi_icmpid =
225*7c478bd9Sstevel@tonic-gate 	    htons(((getpid() & 0xFF) << 8) | (pi->pi_ifindex & 0xFF));
226*7c478bd9Sstevel@tonic-gate 	/*
227*7c478bd9Sstevel@tonic-gate 	 * We optimistically start in the PI_RUNNING state.  Later (in
228*7c478bd9Sstevel@tonic-gate 	 * process_link_state_changes()), we will readjust this to match the
229*7c478bd9Sstevel@tonic-gate 	 * current state of the link.  Further, if test addresses are
230*7c478bd9Sstevel@tonic-gate 	 * subsequently assigned, we will transition to PI_NOTARGETS and then
231*7c478bd9Sstevel@tonic-gate 	 * either PI_RUNNING or PI_FAILED, depending on the result of the test
232*7c478bd9Sstevel@tonic-gate 	 * probes.
233*7c478bd9Sstevel@tonic-gate 	 */
234*7c478bd9Sstevel@tonic-gate 	pi->pi_state = PI_RUNNING;
235*7c478bd9Sstevel@tonic-gate 	pi->pi_flags = PHYINT_FLAGS(flags);
236*7c478bd9Sstevel@tonic-gate 	/*
237*7c478bd9Sstevel@tonic-gate 	 * Initialise the link state.  The link state is initialised to
238*7c478bd9Sstevel@tonic-gate 	 * up, so that if the link is down when IPMP starts monitoring
239*7c478bd9Sstevel@tonic-gate 	 * the interface, it will appear as though there has been a
240*7c478bd9Sstevel@tonic-gate 	 * transition from the link up to link down.  This avoids
241*7c478bd9Sstevel@tonic-gate 	 * having to treat this situation as a special case.
242*7c478bd9Sstevel@tonic-gate 	 */
243*7c478bd9Sstevel@tonic-gate 	INIT_LINK_STATE(pi);
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	/*
246*7c478bd9Sstevel@tonic-gate 	 * Insert the phyint in the list of all phyints, and the
247*7c478bd9Sstevel@tonic-gate 	 * list of phyint group members
248*7c478bd9Sstevel@tonic-gate 	 */
249*7c478bd9Sstevel@tonic-gate 	phyint_insert(pi, pg);
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	/*
252*7c478bd9Sstevel@tonic-gate 	 * If we are joining a failed group, mark the interface as
253*7c478bd9Sstevel@tonic-gate 	 * failed.
254*7c478bd9Sstevel@tonic-gate 	 */
255*7c478bd9Sstevel@tonic-gate 	if (GROUP_FAILED(pg))
256*7c478bd9Sstevel@tonic-gate 		(void) change_lif_flags(pi, IFF_FAILED, _B_TRUE);
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 	return (pi);
259*7c478bd9Sstevel@tonic-gate }
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate /*
262*7c478bd9Sstevel@tonic-gate  * Create a new phyint instance belonging to the phyint 'pi' and address
263*7c478bd9Sstevel@tonic-gate  * family 'af'. Also insert it into the list of all phyint instances by
264*7c478bd9Sstevel@tonic-gate  * calling phyint_inst_insert().
265*7c478bd9Sstevel@tonic-gate  */
266*7c478bd9Sstevel@tonic-gate static struct phyint_instance *
267*7c478bd9Sstevel@tonic-gate phyint_inst_create(struct phyint *pi, int af)
268*7c478bd9Sstevel@tonic-gate {
269*7c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	pii = calloc(1, sizeof (struct phyint_instance));
272*7c478bd9Sstevel@tonic-gate 	if (pii == NULL) {
273*7c478bd9Sstevel@tonic-gate 		logperror("phyint_inst_create: calloc");
274*7c478bd9Sstevel@tonic-gate 		return (NULL);
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	/*
278*7c478bd9Sstevel@tonic-gate 	 * Attach the phyint instance to the phyint.
279*7c478bd9Sstevel@tonic-gate 	 * Set the back pointers as well
280*7c478bd9Sstevel@tonic-gate 	 */
281*7c478bd9Sstevel@tonic-gate 	pii->pii_phyint = pi;
282*7c478bd9Sstevel@tonic-gate 	if (af == AF_INET)
283*7c478bd9Sstevel@tonic-gate 		pi->pi_v4 = pii;
284*7c478bd9Sstevel@tonic-gate 	else
285*7c478bd9Sstevel@tonic-gate 		pi->pi_v6 = pii;
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	pii->pii_in_use = 1;
288*7c478bd9Sstevel@tonic-gate 	pii->pii_probe_sock = -1;
289*7c478bd9Sstevel@tonic-gate 	pii->pii_snxt = 1;
290*7c478bd9Sstevel@tonic-gate 	pii->pii_af = af;
291*7c478bd9Sstevel@tonic-gate 	pii->pii_fd_hrtime = gethrtime() +
292*7c478bd9Sstevel@tonic-gate 	    (FAILURE_DETECTION_QP * (hrtime_t)NANOSEC);
293*7c478bd9Sstevel@tonic-gate 	pii->pii_flags = pi->pi_flags;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	/* Insert the phyint instance in the list of all phyint instances. */
296*7c478bd9Sstevel@tonic-gate 	phyint_inst_insert(pii);
297*7c478bd9Sstevel@tonic-gate 	return (pii);
298*7c478bd9Sstevel@tonic-gate }
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate /*
301*7c478bd9Sstevel@tonic-gate  * Change the state of phyint `pi' to state `state'.
302*7c478bd9Sstevel@tonic-gate  */
303*7c478bd9Sstevel@tonic-gate void
304*7c478bd9Sstevel@tonic-gate phyint_chstate(struct phyint *pi, enum pi_state state)
305*7c478bd9Sstevel@tonic-gate {
306*7c478bd9Sstevel@tonic-gate 	/*
307*7c478bd9Sstevel@tonic-gate 	 * To simplify things, some callers always set a given state
308*7c478bd9Sstevel@tonic-gate 	 * regardless of the previous state of the phyint (e.g., setting
309*7c478bd9Sstevel@tonic-gate 	 * PI_RUNNING when it's already set).  We shouldn't bother
310*7c478bd9Sstevel@tonic-gate 	 * generating an event or consuming a signature for these, since
311*7c478bd9Sstevel@tonic-gate 	 * the actual state of the interface is unchanged.
312*7c478bd9Sstevel@tonic-gate 	 */
313*7c478bd9Sstevel@tonic-gate 	if (pi->pi_state == state)
314*7c478bd9Sstevel@tonic-gate 		return;
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	pi->pi_state = state;
317*7c478bd9Sstevel@tonic-gate 	pi->pi_group->pg_sig++;
318*7c478bd9Sstevel@tonic-gate 	(void) phyint_state_event(pi->pi_group, pi);
319*7c478bd9Sstevel@tonic-gate }
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate /*
322*7c478bd9Sstevel@tonic-gate  * Note that the type of phyint `pi' has changed.
323*7c478bd9Sstevel@tonic-gate  */
324*7c478bd9Sstevel@tonic-gate void
325*7c478bd9Sstevel@tonic-gate phyint_newtype(struct phyint *pi)
326*7c478bd9Sstevel@tonic-gate {
327*7c478bd9Sstevel@tonic-gate 	pi->pi_group->pg_sig++;
328*7c478bd9Sstevel@tonic-gate 	(void) phyint_state_event(pi->pi_group, pi);
329*7c478bd9Sstevel@tonic-gate }
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate /*
332*7c478bd9Sstevel@tonic-gate  * Insert the phyint group in the linked list of all phyint groups
333*7c478bd9Sstevel@tonic-gate  * at the head of the list
334*7c478bd9Sstevel@tonic-gate  */
335*7c478bd9Sstevel@tonic-gate static void
336*7c478bd9Sstevel@tonic-gate phyint_group_insert(struct phyint_group *pg)
337*7c478bd9Sstevel@tonic-gate {
338*7c478bd9Sstevel@tonic-gate 	pg->pg_next = phyint_groups;
339*7c478bd9Sstevel@tonic-gate 	pg->pg_prev = NULL;
340*7c478bd9Sstevel@tonic-gate 	if (phyint_groups != NULL)
341*7c478bd9Sstevel@tonic-gate 		phyint_groups->pg_prev = pg;
342*7c478bd9Sstevel@tonic-gate 	phyint_groups = pg;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	phyint_grouplistsig++;
345*7c478bd9Sstevel@tonic-gate 	(void) phyint_group_change_event(pg, IPMP_GROUP_ADD);
346*7c478bd9Sstevel@tonic-gate }
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate /*
349*7c478bd9Sstevel@tonic-gate  * Create a new phyint group called 'name'.
350*7c478bd9Sstevel@tonic-gate  */
351*7c478bd9Sstevel@tonic-gate static struct phyint_group *
352*7c478bd9Sstevel@tonic-gate phyint_group_create(const char *name)
353*7c478bd9Sstevel@tonic-gate {
354*7c478bd9Sstevel@tonic-gate 	struct	phyint_group *pg;
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
357*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_group_create(%s)\n", name);
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	pg = calloc(1, sizeof (struct phyint_group));
360*7c478bd9Sstevel@tonic-gate 	if (pg == NULL) {
361*7c478bd9Sstevel@tonic-gate 		logperror("phyint_group_create: calloc");
362*7c478bd9Sstevel@tonic-gate 		return (NULL);
363*7c478bd9Sstevel@tonic-gate 	}
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	(void) strncpy(pg->pg_name, name, sizeof (pg->pg_name));
366*7c478bd9Sstevel@tonic-gate 	pg->pg_name[sizeof (pg->pg_name) - 1] = '\0';
367*7c478bd9Sstevel@tonic-gate 	pg->pg_sig = gensig();
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	pg->pg_fdt = user_failure_detection_time;
370*7c478bd9Sstevel@tonic-gate 	pg->pg_probeint = user_probe_interval;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	return (pg);
373*7c478bd9Sstevel@tonic-gate }
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate /*
376*7c478bd9Sstevel@tonic-gate  * Change the state of the phyint group `pg' to state `state'.
377*7c478bd9Sstevel@tonic-gate  */
378*7c478bd9Sstevel@tonic-gate void
379*7c478bd9Sstevel@tonic-gate phyint_group_chstate(struct phyint_group *pg, enum pg_state state)
380*7c478bd9Sstevel@tonic-gate {
381*7c478bd9Sstevel@tonic-gate 	assert(pg != phyint_anongroup);
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	switch (state) {
384*7c478bd9Sstevel@tonic-gate 	case PG_FAILED:
385*7c478bd9Sstevel@tonic-gate 		pg->pg_groupfailed = 1;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 		/*
388*7c478bd9Sstevel@tonic-gate 		 * We can never know with certainty that a group has
389*7c478bd9Sstevel@tonic-gate 		 * failed.  It is possible that all known targets have
390*7c478bd9Sstevel@tonic-gate 		 * failed simultaneously, and new targets have come up
391*7c478bd9Sstevel@tonic-gate 		 * instead. If the targets are routers then router
392*7c478bd9Sstevel@tonic-gate 		 * discovery will kick in, and we will see the new routers
393*7c478bd9Sstevel@tonic-gate 		 * thru routing socket messages. But if the targets are
394*7c478bd9Sstevel@tonic-gate 		 * hosts, we have to discover it by multicast.	So flush
395*7c478bd9Sstevel@tonic-gate 		 * all the host targets. The next probe will send out a
396*7c478bd9Sstevel@tonic-gate 		 * multicast echo request. If this is a group failure, we
397*7c478bd9Sstevel@tonic-gate 		 * will still not see any response, otherwise we will
398*7c478bd9Sstevel@tonic-gate 		 * clear the pg_groupfailed flag after we get
399*7c478bd9Sstevel@tonic-gate 		 * NUM_PROBE_REPAIRS consecutive unicast replies on any
400*7c478bd9Sstevel@tonic-gate 		 * phyint.
401*7c478bd9Sstevel@tonic-gate 		 */
402*7c478bd9Sstevel@tonic-gate 		target_flush_hosts(pg);
403*7c478bd9Sstevel@tonic-gate 		break;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	case PG_RUNNING:
406*7c478bd9Sstevel@tonic-gate 		pg->pg_groupfailed = 0;
407*7c478bd9Sstevel@tonic-gate 		break;
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	default:
410*7c478bd9Sstevel@tonic-gate 		logerr("phyint_group_chstate: invalid group state %d; "
411*7c478bd9Sstevel@tonic-gate 		    "aborting\n", state);
412*7c478bd9Sstevel@tonic-gate 		abort();
413*7c478bd9Sstevel@tonic-gate 	}
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	pg->pg_sig++;
416*7c478bd9Sstevel@tonic-gate 	(void) phyint_group_state_event(pg);
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate /*
420*7c478bd9Sstevel@tonic-gate  * Create a new phyint instance and initialize it from the values supplied by
421*7c478bd9Sstevel@tonic-gate  * the kernel. Always check for ENXIO before logging any error, because the
422*7c478bd9Sstevel@tonic-gate  * interface could have vanished after completion of SIOCGLIFCONF.
423*7c478bd9Sstevel@tonic-gate  * Return values:
424*7c478bd9Sstevel@tonic-gate  *	pointer to the phyint instance on success
425*7c478bd9Sstevel@tonic-gate  *	NULL on failure Eg. if the phyint instance is not found in the kernel
426*7c478bd9Sstevel@tonic-gate  */
427*7c478bd9Sstevel@tonic-gate struct phyint_instance *
428*7c478bd9Sstevel@tonic-gate phyint_inst_init_from_k(int af, char *pi_name)
429*7c478bd9Sstevel@tonic-gate {
430*7c478bd9Sstevel@tonic-gate 	char	pg_name[LIFNAMSIZ + 1];
431*7c478bd9Sstevel@tonic-gate 	int	ifsock;
432*7c478bd9Sstevel@tonic-gate 	uint_t	ifindex;
433*7c478bd9Sstevel@tonic-gate 	uint64_t	flags;
434*7c478bd9Sstevel@tonic-gate 	struct lifreq	lifr;
435*7c478bd9Sstevel@tonic-gate 	struct phyint	*pi;
436*7c478bd9Sstevel@tonic-gate 	struct phyint_instance	*pii;
437*7c478bd9Sstevel@tonic-gate 	boolean_t	pg_created;
438*7c478bd9Sstevel@tonic-gate 	boolean_t	pi_created;
439*7c478bd9Sstevel@tonic-gate 	struct phyint_group	*pg;
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate retry:
442*7c478bd9Sstevel@tonic-gate 	pii = NULL;
443*7c478bd9Sstevel@tonic-gate 	pi = NULL;
444*7c478bd9Sstevel@tonic-gate 	pg = NULL;
445*7c478bd9Sstevel@tonic-gate 	pi_created = _B_FALSE;
446*7c478bd9Sstevel@tonic-gate 	pg_created = _B_FALSE;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
449*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_init_from_k(%s %s)\n",
450*7c478bd9Sstevel@tonic-gate 		    AF_STR(af), pi_name);
451*7c478bd9Sstevel@tonic-gate 	}
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	assert(af == AF_INET || af == AF_INET6);
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	/* Get the socket for doing ioctls */
456*7c478bd9Sstevel@tonic-gate 	ifsock = (af == AF_INET) ? ifsock_v4 : ifsock_v6;
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	/*
459*7c478bd9Sstevel@tonic-gate 	 * Get the interface flags. Ignore loopback and multipoint
460*7c478bd9Sstevel@tonic-gate 	 * interfaces.
461*7c478bd9Sstevel@tonic-gate 	 */
462*7c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi_name, sizeof (lifr.lifr_name));
463*7c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
464*7c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
465*7c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
466*7c478bd9Sstevel@tonic-gate 			logperror("phyint_inst_init_from_k:"
467*7c478bd9Sstevel@tonic-gate 			    " ioctl (get flags)");
468*7c478bd9Sstevel@tonic-gate 		}
469*7c478bd9Sstevel@tonic-gate 		return (NULL);
470*7c478bd9Sstevel@tonic-gate 	}
471*7c478bd9Sstevel@tonic-gate 	flags = lifr.lifr_flags;
472*7c478bd9Sstevel@tonic-gate 	if (!(flags & IFF_MULTICAST) || (flags & IFF_LOOPBACK))
473*7c478bd9Sstevel@tonic-gate 		return (NULL);
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	/*
476*7c478bd9Sstevel@tonic-gate 	 * Get the ifindex for recording later in our tables, in case we need
477*7c478bd9Sstevel@tonic-gate 	 * to create a new phyint.
478*7c478bd9Sstevel@tonic-gate 	 */
479*7c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFINDEX, (char *)&lifr) < 0) {
480*7c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
481*7c478bd9Sstevel@tonic-gate 			logperror("phyint_inst_init_from_k: "
482*7c478bd9Sstevel@tonic-gate 			    " ioctl (get lifindex)");
483*7c478bd9Sstevel@tonic-gate 		}
484*7c478bd9Sstevel@tonic-gate 		return (NULL);
485*7c478bd9Sstevel@tonic-gate 	}
486*7c478bd9Sstevel@tonic-gate 	ifindex = lifr.lifr_index;
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	/*
489*7c478bd9Sstevel@tonic-gate 	 * Get the phyint group name of this phyint, from the kernel.
490*7c478bd9Sstevel@tonic-gate 	 */
491*7c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFGROUPNAME, (char *)&lifr) < 0) {
492*7c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
493*7c478bd9Sstevel@tonic-gate 			logperror("phyint_inst_init_from_k: "
494*7c478bd9Sstevel@tonic-gate 			    "ioctl (get group name)");
495*7c478bd9Sstevel@tonic-gate 		}
496*7c478bd9Sstevel@tonic-gate 		return (NULL);
497*7c478bd9Sstevel@tonic-gate 	}
498*7c478bd9Sstevel@tonic-gate 	(void) strncpy(pg_name, lifr.lifr_groupname, sizeof (pg_name));
499*7c478bd9Sstevel@tonic-gate 	pg_name[sizeof (pg_name) - 1] = '\0';
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	/*
502*7c478bd9Sstevel@tonic-gate 	 * If the phyint is not part of any group, pg_name is the
503*7c478bd9Sstevel@tonic-gate 	 * null string. If 'track_all_phyints' is false, there is no
504*7c478bd9Sstevel@tonic-gate 	 * need to create a phyint.
505*7c478bd9Sstevel@tonic-gate 	 */
506*7c478bd9Sstevel@tonic-gate 	if (pg_name[0] == '\0' && !track_all_phyints) {
507*7c478bd9Sstevel@tonic-gate 		/*
508*7c478bd9Sstevel@tonic-gate 		 * If the IFF_FAILED or IFF_OFFLINE flags are set, reset
509*7c478bd9Sstevel@tonic-gate 		 * them. These flags shouldn't be set if IPMP isn't
510*7c478bd9Sstevel@tonic-gate 		 * tracking the interface.
511*7c478bd9Sstevel@tonic-gate 		 */
512*7c478bd9Sstevel@tonic-gate 		if ((flags & (IFF_FAILED | IFF_OFFLINE)) != 0) {
513*7c478bd9Sstevel@tonic-gate 			lifr.lifr_flags = flags & ~(IFF_FAILED | IFF_OFFLINE);
514*7c478bd9Sstevel@tonic-gate 			if (ioctl(ifsock, SIOCSLIFFLAGS, (char *)&lifr) < 0) {
515*7c478bd9Sstevel@tonic-gate 				if (errno != ENXIO) {
516*7c478bd9Sstevel@tonic-gate 					logperror("phyint_inst_init_from_k:"
517*7c478bd9Sstevel@tonic-gate 					    " ioctl (set flags)");
518*7c478bd9Sstevel@tonic-gate 				}
519*7c478bd9Sstevel@tonic-gate 			}
520*7c478bd9Sstevel@tonic-gate 		}
521*7c478bd9Sstevel@tonic-gate 		return (NULL);
522*7c478bd9Sstevel@tonic-gate 	}
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	/*
525*7c478bd9Sstevel@tonic-gate 	 * We need to create a new phyint instance. A phyint instance
526*7c478bd9Sstevel@tonic-gate 	 * belongs to a phyint, and the phyint belongs to a phyint group.
527*7c478bd9Sstevel@tonic-gate 	 * So we first lookup the 'parents' and if they don't exist then
528*7c478bd9Sstevel@tonic-gate 	 * we create them.
529*7c478bd9Sstevel@tonic-gate 	 */
530*7c478bd9Sstevel@tonic-gate 	pg = phyint_group_lookup(pg_name);
531*7c478bd9Sstevel@tonic-gate 	if (pg == NULL) {
532*7c478bd9Sstevel@tonic-gate 		pg = phyint_group_create(pg_name);
533*7c478bd9Sstevel@tonic-gate 		if (pg == NULL) {
534*7c478bd9Sstevel@tonic-gate 			logerr("phyint_inst_init_from_k:"
535*7c478bd9Sstevel@tonic-gate 			    " unable to create group %s\n", pg_name);
536*7c478bd9Sstevel@tonic-gate 			return (NULL);
537*7c478bd9Sstevel@tonic-gate 		}
538*7c478bd9Sstevel@tonic-gate 		phyint_group_insert(pg);
539*7c478bd9Sstevel@tonic-gate 		pg_created = _B_TRUE;
540*7c478bd9Sstevel@tonic-gate 	}
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	/*
543*7c478bd9Sstevel@tonic-gate 	 * Lookup the phyint. If the phyint does not exist create it.
544*7c478bd9Sstevel@tonic-gate 	 */
545*7c478bd9Sstevel@tonic-gate 	pi = phyint_lookup(pi_name);
546*7c478bd9Sstevel@tonic-gate 	if (pi == NULL) {
547*7c478bd9Sstevel@tonic-gate 		pi = phyint_create(pi_name, pg, ifindex, flags);
548*7c478bd9Sstevel@tonic-gate 		if (pi == NULL) {
549*7c478bd9Sstevel@tonic-gate 			logerr("phyint_inst_init_from_k:"
550*7c478bd9Sstevel@tonic-gate 			    " unable to create phyint %s\n", pi_name);
551*7c478bd9Sstevel@tonic-gate 			if (pg_created)
552*7c478bd9Sstevel@tonic-gate 				phyint_group_delete(pg);
553*7c478bd9Sstevel@tonic-gate 			return (NULL);
554*7c478bd9Sstevel@tonic-gate 		}
555*7c478bd9Sstevel@tonic-gate 		pi_created = _B_TRUE;
556*7c478bd9Sstevel@tonic-gate 	} else {
557*7c478bd9Sstevel@tonic-gate 		/* The phyint exists already. */
558*7c478bd9Sstevel@tonic-gate 		assert(pi_created == _B_FALSE);
559*7c478bd9Sstevel@tonic-gate 		/*
560*7c478bd9Sstevel@tonic-gate 		 * Normally we should see consistent values for the IPv4 and
561*7c478bd9Sstevel@tonic-gate 		 * IPv6 instances, for phyint properties. If we don't, it
562*7c478bd9Sstevel@tonic-gate 		 * means things have changed underneath us, and we should
563*7c478bd9Sstevel@tonic-gate 		 * resync our tables with the kernel. Check whether the
564*7c478bd9Sstevel@tonic-gate 		 * interface index has changed. If so, it is most likely
565*7c478bd9Sstevel@tonic-gate 		 * the interface has been unplumbed and replumbed,
566*7c478bd9Sstevel@tonic-gate 		 * while we are yet to update our tables. Do it now.
567*7c478bd9Sstevel@tonic-gate 		 */
568*7c478bd9Sstevel@tonic-gate 		if (pi->pi_ifindex != ifindex) {
569*7c478bd9Sstevel@tonic-gate 			if (pg_created)
570*7c478bd9Sstevel@tonic-gate 				phyint_group_delete(pg);
571*7c478bd9Sstevel@tonic-gate 			phyint_inst_delete(PHYINT_INSTANCE(pi, AF_OTHER(af)));
572*7c478bd9Sstevel@tonic-gate 			goto retry;
573*7c478bd9Sstevel@tonic-gate 		}
574*7c478bd9Sstevel@tonic-gate 		assert(PHYINT_INSTANCE(pi, af) == NULL);
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 		/*
577*7c478bd9Sstevel@tonic-gate 		 * If the group name seen by the IPv4 and IPv6 instances
578*7c478bd9Sstevel@tonic-gate 		 * are different, it is most likely the groupname has
579*7c478bd9Sstevel@tonic-gate 		 * changed, while we are yet to update our tables. Do it now.
580*7c478bd9Sstevel@tonic-gate 		 */
581*7c478bd9Sstevel@tonic-gate 		if (strcmp(pi->pi_group->pg_name, pg_name) != 0) {
582*7c478bd9Sstevel@tonic-gate 			if (pg_created)
583*7c478bd9Sstevel@tonic-gate 				phyint_group_delete(pg);
584*7c478bd9Sstevel@tonic-gate 			restore_phyint(pi);
585*7c478bd9Sstevel@tonic-gate 			phyint_inst_delete(PHYINT_INSTANCE(pi,
586*7c478bd9Sstevel@tonic-gate 			    AF_OTHER(af)));
587*7c478bd9Sstevel@tonic-gate 			goto retry;
588*7c478bd9Sstevel@tonic-gate 		}
589*7c478bd9Sstevel@tonic-gate 	}
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	/*
592*7c478bd9Sstevel@tonic-gate 	 * Create a new phyint instance, corresponding to the 'af'
593*7c478bd9Sstevel@tonic-gate 	 * passed in.
594*7c478bd9Sstevel@tonic-gate 	 */
595*7c478bd9Sstevel@tonic-gate 	pii = phyint_inst_create(pi, af);
596*7c478bd9Sstevel@tonic-gate 	if (pii == NULL) {
597*7c478bd9Sstevel@tonic-gate 		logerr("phyint_inst_init_from_k: unable to create"
598*7c478bd9Sstevel@tonic-gate 		    "phyint inst %s\n", pi->pi_name);
599*7c478bd9Sstevel@tonic-gate 		if (pi_created) {
600*7c478bd9Sstevel@tonic-gate 			/*
601*7c478bd9Sstevel@tonic-gate 			 * Deleting the phyint will delete the phyint group
602*7c478bd9Sstevel@tonic-gate 			 * if this is the last phyint in the group.
603*7c478bd9Sstevel@tonic-gate 			 */
604*7c478bd9Sstevel@tonic-gate 			phyint_delete(pi);
605*7c478bd9Sstevel@tonic-gate 		}
606*7c478bd9Sstevel@tonic-gate 		return (NULL);
607*7c478bd9Sstevel@tonic-gate 	}
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 	return (pii);
610*7c478bd9Sstevel@tonic-gate }
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate /*
613*7c478bd9Sstevel@tonic-gate  * Bind the pii_probe_sock to the chosen IFF_NOFAILOVER address in
614*7c478bd9Sstevel@tonic-gate  * pii_probe_logint. This socket will be used for sending and receiving
615*7c478bd9Sstevel@tonic-gate  * ICMP/ICMPv6 probes to targets. Do the common part in this function, and
616*7c478bd9Sstevel@tonic-gate  * complete the initializations by calling the protocol specific functions
617*7c478bd9Sstevel@tonic-gate  * phyint_inst_v{4,6}_sockinit() respectively.
618*7c478bd9Sstevel@tonic-gate  *
619*7c478bd9Sstevel@tonic-gate  * Return values: _B_TRUE/_B_FALSE for success or failure respectively.
620*7c478bd9Sstevel@tonic-gate  */
621*7c478bd9Sstevel@tonic-gate boolean_t
622*7c478bd9Sstevel@tonic-gate phyint_inst_sockinit(struct phyint_instance *pii)
623*7c478bd9Sstevel@tonic-gate {
624*7c478bd9Sstevel@tonic-gate 	boolean_t success;
625*7c478bd9Sstevel@tonic-gate 	struct phyint_group *pg;
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
628*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_sockinit(%s %s)\n",
629*7c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name);
630*7c478bd9Sstevel@tonic-gate 	}
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_probe_logint != NULL);
633*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_probe_logint->li_flags & IFF_UP);
634*7c478bd9Sstevel@tonic-gate 	assert(SINGLETON_GROUP(pii->pii_phyint) ||
635*7c478bd9Sstevel@tonic-gate 	    (pii->pii_probe_logint->li_flags & IFF_NOFAILOVER));
636*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_af == AF_INET || pii->pii_af == AF_INET6);
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 	/*
639*7c478bd9Sstevel@tonic-gate 	 * If the socket is already bound, close pii_probe_sock
640*7c478bd9Sstevel@tonic-gate 	 */
641*7c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock != -1)
642*7c478bd9Sstevel@tonic-gate 		close_probe_socket(pii, _B_TRUE);
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 	/*
645*7c478bd9Sstevel@tonic-gate 	 * If the phyint is not part of a named group and track_all_phyints is
646*7c478bd9Sstevel@tonic-gate 	 * false, simply return.
647*7c478bd9Sstevel@tonic-gate 	 */
648*7c478bd9Sstevel@tonic-gate 	pg = pii->pii_phyint->pi_group;
649*7c478bd9Sstevel@tonic-gate 	if (pg == phyint_anongroup && !track_all_phyints) {
650*7c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT)
651*7c478bd9Sstevel@tonic-gate 			logdebug("phyint_inst_sockinit: no group\n");
652*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
653*7c478bd9Sstevel@tonic-gate 	}
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	/*
656*7c478bd9Sstevel@tonic-gate 	 * Initialize the socket by calling the protocol specific function.
657*7c478bd9Sstevel@tonic-gate 	 * If it succeeds, add the socket to the poll list.
658*7c478bd9Sstevel@tonic-gate 	 */
659*7c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET6)
660*7c478bd9Sstevel@tonic-gate 		success = phyint_inst_v6_sockinit(pii);
661*7c478bd9Sstevel@tonic-gate 	else
662*7c478bd9Sstevel@tonic-gate 		success = phyint_inst_v4_sockinit(pii);
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	if (success && (poll_add(pii->pii_probe_sock) == 0))
665*7c478bd9Sstevel@tonic-gate 		return (_B_TRUE);
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	/* Something failed, cleanup and return false */
668*7c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock != -1)
669*7c478bd9Sstevel@tonic-gate 		close_probe_socket(pii, _B_FALSE);
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	return (_B_FALSE);
672*7c478bd9Sstevel@tonic-gate }
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate /*
675*7c478bd9Sstevel@tonic-gate  * IPv6 specific part in initializing the pii_probe_sock. This socket is
676*7c478bd9Sstevel@tonic-gate  * used to send/receive ICMPv6 probe packets.
677*7c478bd9Sstevel@tonic-gate  */
678*7c478bd9Sstevel@tonic-gate static boolean_t
679*7c478bd9Sstevel@tonic-gate phyint_inst_v6_sockinit(struct phyint_instance *pii)
680*7c478bd9Sstevel@tonic-gate {
681*7c478bd9Sstevel@tonic-gate 	icmp6_filter_t filter;
682*7c478bd9Sstevel@tonic-gate 	int hopcount = 1;
683*7c478bd9Sstevel@tonic-gate 	int int_op;
684*7c478bd9Sstevel@tonic-gate 	struct	sockaddr_in6	testaddr;
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 	/*
687*7c478bd9Sstevel@tonic-gate 	 * Open a raw socket with ICMPv6 protocol.
688*7c478bd9Sstevel@tonic-gate 	 *
689*7c478bd9Sstevel@tonic-gate 	 * Use IPV6_DONTFAILOVER_IF to make sure that probes go out
690*7c478bd9Sstevel@tonic-gate 	 * on the specified phyint only, and are not subject to load
691*7c478bd9Sstevel@tonic-gate 	 * balancing. Bind to the src address chosen will ensure that
692*7c478bd9Sstevel@tonic-gate 	 * the responses are received only on the specified phyint.
693*7c478bd9Sstevel@tonic-gate 	 *
694*7c478bd9Sstevel@tonic-gate 	 * Set the hopcount to 1 so that probe packets are not routed.
695*7c478bd9Sstevel@tonic-gate 	 * Disable multicast loopback. Set the receive filter to
696*7c478bd9Sstevel@tonic-gate 	 * receive only ICMPv6 echo replies.
697*7c478bd9Sstevel@tonic-gate 	 */
698*7c478bd9Sstevel@tonic-gate 	pii->pii_probe_sock = socket(pii->pii_af, SOCK_RAW, IPPROTO_ICMPV6);
699*7c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock < 0) {
700*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: socket");
701*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
702*7c478bd9Sstevel@tonic-gate }
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 	bzero(&testaddr, sizeof (testaddr));
705*7c478bd9Sstevel@tonic-gate 	testaddr.sin6_family = AF_INET6;
706*7c478bd9Sstevel@tonic-gate 	testaddr.sin6_port = 0;
707*7c478bd9Sstevel@tonic-gate 	testaddr.sin6_addr = pii->pii_probe_logint->li_addr;
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	if (bind(pii->pii_probe_sock, (struct sockaddr *)&testaddr,
710*7c478bd9Sstevel@tonic-gate 	    sizeof (testaddr)) < 0) {
711*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: IPv6 bind");
712*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
713*7c478bd9Sstevel@tonic-gate 	}
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	/*
716*7c478bd9Sstevel@tonic-gate 	 * IPV6_DONTFAILOVER_IF option takes precedence over setting
717*7c478bd9Sstevel@tonic-gate 	 * IP_MULTICAST_IF. So we don't set IPV6_MULTICAST_IF again.
718*7c478bd9Sstevel@tonic-gate 	 */
719*7c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_DONTFAILOVER_IF,
720*7c478bd9Sstevel@tonic-gate 	    (char *)&pii->pii_ifindex, sizeof (uint_t)) < 0) {
721*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
722*7c478bd9Sstevel@tonic-gate 		    " IPV6_DONTFAILOVER_IF");
723*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
724*7c478bd9Sstevel@tonic-gate 	}
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
727*7c478bd9Sstevel@tonic-gate 	    (char *)&hopcount, sizeof (hopcount)) < 0) {
728*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
729*7c478bd9Sstevel@tonic-gate 		    " IPV6_UNICAST_HOPS");
730*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
734*7c478bd9Sstevel@tonic-gate 	    (char *)&hopcount, sizeof (hopcount)) < 0) {
735*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
736*7c478bd9Sstevel@tonic-gate 		    " IPV6_MULTICAST_HOPS");
737*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
738*7c478bd9Sstevel@tonic-gate 	}
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	int_op = 0;	/* used to turn off option */
741*7c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
742*7c478bd9Sstevel@tonic-gate 	    (char *)&int_op, sizeof (int_op)) < 0) {
743*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
744*7c478bd9Sstevel@tonic-gate 		    " IPV6_MULTICAST_LOOP");
745*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
746*7c478bd9Sstevel@tonic-gate 	}
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	/*
749*7c478bd9Sstevel@tonic-gate 	 * Filter out so that we only receive ICMP echo replies
750*7c478bd9Sstevel@tonic-gate 	 */
751*7c478bd9Sstevel@tonic-gate 	ICMP6_FILTER_SETBLOCKALL(&filter);
752*7c478bd9Sstevel@tonic-gate 	ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_ICMPV6, ICMP6_FILTER,
755*7c478bd9Sstevel@tonic-gate 	    (char *)&filter, sizeof (filter)) < 0) {
756*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
757*7c478bd9Sstevel@tonic-gate 		    " ICMP6_FILTER");
758*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 	/* Enable receipt of ancillary data */
762*7c478bd9Sstevel@tonic-gate 	int_op = 1;
763*7c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
764*7c478bd9Sstevel@tonic-gate 	    (char *)&int_op, sizeof (int_op)) < 0) {
765*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v6_sockinit: setsockopt"
766*7c478bd9Sstevel@tonic-gate 		    " IPV6_RECVHOPLIMIT");
767*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
768*7c478bd9Sstevel@tonic-gate 	}
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
771*7c478bd9Sstevel@tonic-gate }
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate /*
774*7c478bd9Sstevel@tonic-gate  * IPv4 specific part in initializing the pii_probe_sock. This socket is
775*7c478bd9Sstevel@tonic-gate  * used to send/receive ICMPv4 probe packets.
776*7c478bd9Sstevel@tonic-gate  */
777*7c478bd9Sstevel@tonic-gate static boolean_t
778*7c478bd9Sstevel@tonic-gate phyint_inst_v4_sockinit(struct phyint_instance *pii)
779*7c478bd9Sstevel@tonic-gate {
780*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in  testaddr;
781*7c478bd9Sstevel@tonic-gate 	char	char_op;
782*7c478bd9Sstevel@tonic-gate 	int	ttl = 1;
783*7c478bd9Sstevel@tonic-gate 	char	char_ttl = 1;
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 	/*
786*7c478bd9Sstevel@tonic-gate 	 * Open a raw socket with ICMPv4 protocol.
787*7c478bd9Sstevel@tonic-gate 	 *
788*7c478bd9Sstevel@tonic-gate 	 * Use IP_DONTFAILOVER_IF to make sure that probes go out
789*7c478bd9Sstevel@tonic-gate 	 * on the specified phyint only, and are not subject to load
790*7c478bd9Sstevel@tonic-gate 	 * balancing. Bind to the src address chosen will ensure that
791*7c478bd9Sstevel@tonic-gate 	 * the responses are received only on the specified phyint.
792*7c478bd9Sstevel@tonic-gate 	 *
793*7c478bd9Sstevel@tonic-gate 	 * Set the ttl to 1 so that probe packets are not routed.
794*7c478bd9Sstevel@tonic-gate 	 * Disable multicast loopback.
795*7c478bd9Sstevel@tonic-gate 	 */
796*7c478bd9Sstevel@tonic-gate 	pii->pii_probe_sock = socket(pii->pii_af, SOCK_RAW, IPPROTO_ICMP);
797*7c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock < 0) {
798*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: socket");
799*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
800*7c478bd9Sstevel@tonic-gate 	}
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	bzero(&testaddr, sizeof (testaddr));
803*7c478bd9Sstevel@tonic-gate 	testaddr.sin_family = AF_INET;
804*7c478bd9Sstevel@tonic-gate 	testaddr.sin_port = 0;
805*7c478bd9Sstevel@tonic-gate 	IN6_V4MAPPED_TO_INADDR(&pii->pii_probe_logint->li_addr,
806*7c478bd9Sstevel@tonic-gate 	    &testaddr.sin_addr);
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 	if (bind(pii->pii_probe_sock, (struct sockaddr *)&testaddr,
809*7c478bd9Sstevel@tonic-gate 	    sizeof (testaddr)) < 0) {
810*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: IPv4 bind");
811*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
812*7c478bd9Sstevel@tonic-gate 	}
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 	/*
815*7c478bd9Sstevel@tonic-gate 	 * IP_DONTFAILOVER_IF option takes precedence over setting
816*7c478bd9Sstevel@tonic-gate 	 * IP_MULTICAST_IF. So we don't set IP_MULTICAST_IF again.
817*7c478bd9Sstevel@tonic-gate 	 */
818*7c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_DONTFAILOVER_IF,
819*7c478bd9Sstevel@tonic-gate 	    (char *)&testaddr.sin_addr, sizeof (struct in_addr)) < 0) {
820*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
821*7c478bd9Sstevel@tonic-gate 		    " IP_DONTFAILOVER");
822*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
823*7c478bd9Sstevel@tonic-gate 	}
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_TTL,
826*7c478bd9Sstevel@tonic-gate 	    (char *)&ttl, sizeof (ttl)) < 0) {
827*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
828*7c478bd9Sstevel@tonic-gate 		    " IP_TTL");
829*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
830*7c478bd9Sstevel@tonic-gate 	}
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	char_op = 0;	/* used to turn off option */
833*7c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
834*7c478bd9Sstevel@tonic-gate 	    (char *)&char_op, sizeof (char_op)) == -1) {
835*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
836*7c478bd9Sstevel@tonic-gate 		    " IP_MULTICAST_LOOP");
837*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
838*7c478bd9Sstevel@tonic-gate 	}
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 	if (setsockopt(pii->pii_probe_sock, IPPROTO_IP, IP_MULTICAST_TTL,
841*7c478bd9Sstevel@tonic-gate 	    (char *)&char_ttl, sizeof (char_ttl)) == -1) {
842*7c478bd9Sstevel@tonic-gate 		logperror_pii(pii, "phyint_inst_v4_sockinit: setsockopt"
843*7c478bd9Sstevel@tonic-gate 		    " IP_MULTICAST_TTL");
844*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
845*7c478bd9Sstevel@tonic-gate 	}
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
848*7c478bd9Sstevel@tonic-gate }
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate /*
851*7c478bd9Sstevel@tonic-gate  * Remove the phyint group from the list of 'all phyint groups'
852*7c478bd9Sstevel@tonic-gate  * and free it.
853*7c478bd9Sstevel@tonic-gate  */
854*7c478bd9Sstevel@tonic-gate static void
855*7c478bd9Sstevel@tonic-gate phyint_group_delete(struct phyint_group *pg)
856*7c478bd9Sstevel@tonic-gate {
857*7c478bd9Sstevel@tonic-gate 	/*
858*7c478bd9Sstevel@tonic-gate 	 * The anonymous group always exists, even when empty.
859*7c478bd9Sstevel@tonic-gate 	 */
860*7c478bd9Sstevel@tonic-gate 	if (pg == phyint_anongroup)
861*7c478bd9Sstevel@tonic-gate 		return;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
864*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_group_delete('%s')\n", pg->pg_name);
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	/*
867*7c478bd9Sstevel@tonic-gate 	 * The phyint group must be empty, and must not have any phyints.
868*7c478bd9Sstevel@tonic-gate 	 * The phyint group must be in the list of all phyint groups
869*7c478bd9Sstevel@tonic-gate 	 */
870*7c478bd9Sstevel@tonic-gate 	assert(pg->pg_phyint == NULL);
871*7c478bd9Sstevel@tonic-gate 	assert(phyint_groups == pg || pg->pg_prev != NULL);
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	if (pg->pg_prev != NULL)
874*7c478bd9Sstevel@tonic-gate 		pg->pg_prev->pg_next = pg->pg_next;
875*7c478bd9Sstevel@tonic-gate 	else
876*7c478bd9Sstevel@tonic-gate 		phyint_groups = pg->pg_next;
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 	if (pg->pg_next != NULL)
879*7c478bd9Sstevel@tonic-gate 		pg->pg_next->pg_prev = pg->pg_prev;
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 	pg->pg_next = NULL;
882*7c478bd9Sstevel@tonic-gate 	pg->pg_prev = NULL;
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 	phyint_grouplistsig++;
885*7c478bd9Sstevel@tonic-gate 	(void) phyint_group_change_event(pg, IPMP_GROUP_REMOVE);
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	free(pg);
888*7c478bd9Sstevel@tonic-gate }
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate /*
891*7c478bd9Sstevel@tonic-gate  * Extract information from the kernel about the desired phyint.
892*7c478bd9Sstevel@tonic-gate  * Look only for properties of the phyint and not properties of logints.
893*7c478bd9Sstevel@tonic-gate  * Take appropriate action on the changes.
894*7c478bd9Sstevel@tonic-gate  * Return codes:
895*7c478bd9Sstevel@tonic-gate  *	PI_OK
896*7c478bd9Sstevel@tonic-gate  *		The phyint exists in the kernel and matches our knowledge
897*7c478bd9Sstevel@tonic-gate  *		of the phyint.
898*7c478bd9Sstevel@tonic-gate  *	PI_DELETED
899*7c478bd9Sstevel@tonic-gate  *		The phyint has vanished in the kernel.
900*7c478bd9Sstevel@tonic-gate  *	PI_IFINDEX_CHANGED
901*7c478bd9Sstevel@tonic-gate  *		The phyint's interface index has changed.
902*7c478bd9Sstevel@tonic-gate  *		Ask the caller to delete and recreate the phyint.
903*7c478bd9Sstevel@tonic-gate  *	PI_IOCTL_ERROR
904*7c478bd9Sstevel@tonic-gate  *		Some ioctl error. Don't change anything.
905*7c478bd9Sstevel@tonic-gate  *	PI_GROUP_CHANGED
906*7c478bd9Sstevel@tonic-gate  *		The phyint has changed group.
907*7c478bd9Sstevel@tonic-gate  */
908*7c478bd9Sstevel@tonic-gate int
909*7c478bd9Sstevel@tonic-gate phyint_inst_update_from_k(struct phyint_instance *pii)
910*7c478bd9Sstevel@tonic-gate {
911*7c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
912*7c478bd9Sstevel@tonic-gate 	int	ifsock;
913*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 	pi = pii->pii_phyint;
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
918*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_update_from_k(%s %s)\n",
919*7c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pi->pi_name);
920*7c478bd9Sstevel@tonic-gate 	}
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	/*
923*7c478bd9Sstevel@tonic-gate 	 * Get the ifindex from the kernel, for comparison with the
924*7c478bd9Sstevel@tonic-gate 	 * value in our tables.
925*7c478bd9Sstevel@tonic-gate 	 */
926*7c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
927*7c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 	ifsock = (pii->pii_af == AF_INET) ? ifsock_v4 : ifsock_v6;
930*7c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFINDEX, &lifr) < 0) {
931*7c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
932*7c478bd9Sstevel@tonic-gate 			return (PI_DELETED);
933*7c478bd9Sstevel@tonic-gate 		} else {
934*7c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "phyint_inst_update_from_k:"
935*7c478bd9Sstevel@tonic-gate 			    " ioctl (get lifindex)");
936*7c478bd9Sstevel@tonic-gate 			return (PI_IOCTL_ERROR);
937*7c478bd9Sstevel@tonic-gate 		}
938*7c478bd9Sstevel@tonic-gate 	}
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 	if (lifr.lifr_index != pi->pi_ifindex) {
941*7c478bd9Sstevel@tonic-gate 		/*
942*7c478bd9Sstevel@tonic-gate 		 * The index has changed. Most likely the interface has
943*7c478bd9Sstevel@tonic-gate 		 * been unplumbed and replumbed. Ask the caller to take
944*7c478bd9Sstevel@tonic-gate 		 * appropriate action.
945*7c478bd9Sstevel@tonic-gate 		 */
946*7c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT) {
947*7c478bd9Sstevel@tonic-gate 			logdebug("phyint_inst_update_from_k:"
948*7c478bd9Sstevel@tonic-gate 			    " old index %d new index %d\n",
949*7c478bd9Sstevel@tonic-gate 			    pi->pi_ifindex, lifr.lifr_index);
950*7c478bd9Sstevel@tonic-gate 		}
951*7c478bd9Sstevel@tonic-gate 		return (PI_IFINDEX_CHANGED);
952*7c478bd9Sstevel@tonic-gate 	}
953*7c478bd9Sstevel@tonic-gate 
954*7c478bd9Sstevel@tonic-gate 	/*
955*7c478bd9Sstevel@tonic-gate 	 * Get the group name from the kernel, for comparison with
956*7c478bd9Sstevel@tonic-gate 	 * the value in our tables.
957*7c478bd9Sstevel@tonic-gate 	 */
958*7c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFGROUPNAME, &lifr) < 0) {
959*7c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
960*7c478bd9Sstevel@tonic-gate 			return (PI_DELETED);
961*7c478bd9Sstevel@tonic-gate 		} else {
962*7c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "phyint_inst_update_from_k:"
963*7c478bd9Sstevel@tonic-gate 			    " ioctl (get groupname)");
964*7c478bd9Sstevel@tonic-gate 			return (PI_IOCTL_ERROR);
965*7c478bd9Sstevel@tonic-gate 		}
966*7c478bd9Sstevel@tonic-gate 	}
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 	/*
969*7c478bd9Sstevel@tonic-gate 	 * If the phyint has changed group i.e. if the phyint group name
970*7c478bd9Sstevel@tonic-gate 	 * returned by the kernel is different, ask the caller to delete
971*7c478bd9Sstevel@tonic-gate 	 * and recreate the phyint in the right group
972*7c478bd9Sstevel@tonic-gate 	 */
973*7c478bd9Sstevel@tonic-gate 	if (strcmp(lifr.lifr_groupname, pi->pi_group->pg_name) != 0) {
974*7c478bd9Sstevel@tonic-gate 		/* Groupname has changed */
975*7c478bd9Sstevel@tonic-gate 		if (debug & D_PHYINT) {
976*7c478bd9Sstevel@tonic-gate 			logdebug("phyint_inst_update_from_k:"
977*7c478bd9Sstevel@tonic-gate 			    " groupname change\n");
978*7c478bd9Sstevel@tonic-gate 		}
979*7c478bd9Sstevel@tonic-gate 		return (PI_GROUP_CHANGED);
980*7c478bd9Sstevel@tonic-gate 	}
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	/*
983*7c478bd9Sstevel@tonic-gate 	 * Get the current phyint flags from the kernel, and determine what
984*7c478bd9Sstevel@tonic-gate 	 * flags have changed by comparing against our tables.	Note that the
985*7c478bd9Sstevel@tonic-gate 	 * IFF_INACTIVE processing in initifs() relies on this call to ensure
986*7c478bd9Sstevel@tonic-gate 	 * that IFF_INACTIVE is really still set on the interface.
987*7c478bd9Sstevel@tonic-gate 	 */
988*7c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFFLAGS, &lifr) < 0) {
989*7c478bd9Sstevel@tonic-gate 		if (errno == ENXIO) {
990*7c478bd9Sstevel@tonic-gate 			return (PI_DELETED);
991*7c478bd9Sstevel@tonic-gate 		} else {
992*7c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "phyint_inst_update_from_k: "
993*7c478bd9Sstevel@tonic-gate 			    " ioctl (get flags)");
994*7c478bd9Sstevel@tonic-gate 			return (PI_IOCTL_ERROR);
995*7c478bd9Sstevel@tonic-gate 		}
996*7c478bd9Sstevel@tonic-gate 	}
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate 	pi->pi_flags = PHYINT_FLAGS(lifr.lifr_flags);
999*7c478bd9Sstevel@tonic-gate 	if (pi->pi_v4 != NULL)
1000*7c478bd9Sstevel@tonic-gate 		pi->pi_v4->pii_flags = pi->pi_flags;
1001*7c478bd9Sstevel@tonic-gate 	if (pi->pi_v6 != NULL)
1002*7c478bd9Sstevel@tonic-gate 		pi->pi_v6->pii_flags = pi->pi_flags;
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 	if (pi->pi_flags & IFF_FAILED) {
1005*7c478bd9Sstevel@tonic-gate 		/*
1006*7c478bd9Sstevel@tonic-gate 		 * If we are in the running and full state, we have
1007*7c478bd9Sstevel@tonic-gate 		 * completed failbacks successfully and we would have
1008*7c478bd9Sstevel@tonic-gate 		 * expected IFF_FAILED to have been clear. That it is
1009*7c478bd9Sstevel@tonic-gate 		 * set means there was a race condition. Some other
1010*7c478bd9Sstevel@tonic-gate 		 * process turned on the IFF_FAILED flag. Since the
1011*7c478bd9Sstevel@tonic-gate 		 * flag setting is not atomic, i.e. a get ioctl followed
1012*7c478bd9Sstevel@tonic-gate 		 * by a set ioctl, and since there is no way to set an
1013*7c478bd9Sstevel@tonic-gate 		 * individual flag bit, this could have occurred.
1014*7c478bd9Sstevel@tonic-gate 		 */
1015*7c478bd9Sstevel@tonic-gate 		if (pi->pi_state == PI_RUNNING && pi->pi_full)
1016*7c478bd9Sstevel@tonic-gate 			(void) change_lif_flags(pi, IFF_FAILED, _B_FALSE);
1017*7c478bd9Sstevel@tonic-gate 	} else {
1018*7c478bd9Sstevel@tonic-gate 		/*
1019*7c478bd9Sstevel@tonic-gate 		 * If we are in the failed state, there was a race.
1020*7c478bd9Sstevel@tonic-gate 		 * we have completed failover successfully because our
1021*7c478bd9Sstevel@tonic-gate 		 * state is failed and empty. Some other process turned
1022*7c478bd9Sstevel@tonic-gate 		 * off the IFF_FAILED flag. Same comment as above
1023*7c478bd9Sstevel@tonic-gate 		 */
1024*7c478bd9Sstevel@tonic-gate 		if (pi->pi_state == PI_FAILED && pi->pi_empty)
1025*7c478bd9Sstevel@tonic-gate 			(void) change_lif_flags(pi, IFF_FAILED, _B_TRUE);
1026*7c478bd9Sstevel@tonic-gate 	}
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate 	/* No change in phyint status */
1029*7c478bd9Sstevel@tonic-gate 	return (PI_OK);
1030*7c478bd9Sstevel@tonic-gate }
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate /*
1033*7c478bd9Sstevel@tonic-gate  * Delete the phyint. Remove it from the list of all phyints, and the
1034*7c478bd9Sstevel@tonic-gate  * list of phyint group members. If the group becomes empty, delete the
1035*7c478bd9Sstevel@tonic-gate  * group also.
1036*7c478bd9Sstevel@tonic-gate  */
1037*7c478bd9Sstevel@tonic-gate static void
1038*7c478bd9Sstevel@tonic-gate phyint_delete(struct phyint *pi)
1039*7c478bd9Sstevel@tonic-gate {
1040*7c478bd9Sstevel@tonic-gate 	struct phyint_group *pg = pi->pi_group;
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
1043*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_delete(%s)\n", pi->pi_name);
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate 	/* Both IPv4 and IPv6 phyint instances must have been deleted. */
1046*7c478bd9Sstevel@tonic-gate 	assert(pi->pi_v4 == NULL && pi->pi_v6 == NULL);
1047*7c478bd9Sstevel@tonic-gate 
1048*7c478bd9Sstevel@tonic-gate 	/*
1049*7c478bd9Sstevel@tonic-gate 	 * The phyint must belong to a group.
1050*7c478bd9Sstevel@tonic-gate 	 */
1051*7c478bd9Sstevel@tonic-gate 	assert(pg->pg_phyint == pi || pi->pi_pgprev != NULL);
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 	/* The phyint must be in the list of all phyints */
1054*7c478bd9Sstevel@tonic-gate 	assert(phyints == pi || pi->pi_prev != NULL);
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate 	/* Remove the phyint from the phyint group list */
1057*7c478bd9Sstevel@tonic-gate 	pg->pg_sig++;
1058*7c478bd9Sstevel@tonic-gate 	(void) phyint_group_member_event(pg, pi, IPMP_IF_REMOVE);
1059*7c478bd9Sstevel@tonic-gate 
1060*7c478bd9Sstevel@tonic-gate 	if (pi->pi_pgprev == NULL) {
1061*7c478bd9Sstevel@tonic-gate 		/* Phyint is the 1st in the phyint group list */
1062*7c478bd9Sstevel@tonic-gate 		pg->pg_phyint = pi->pi_pgnext;
1063*7c478bd9Sstevel@tonic-gate 	} else {
1064*7c478bd9Sstevel@tonic-gate 		pi->pi_pgprev->pi_pgnext = pi->pi_pgnext;
1065*7c478bd9Sstevel@tonic-gate 	}
1066*7c478bd9Sstevel@tonic-gate 	if (pi->pi_pgnext != NULL)
1067*7c478bd9Sstevel@tonic-gate 		pi->pi_pgnext->pi_pgprev = pi->pi_pgprev;
1068*7c478bd9Sstevel@tonic-gate 	pi->pi_pgnext = NULL;
1069*7c478bd9Sstevel@tonic-gate 	pi->pi_pgprev = NULL;
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	/* Remove the phyint from the global list of phyints */
1072*7c478bd9Sstevel@tonic-gate 	if (pi->pi_prev == NULL) {
1073*7c478bd9Sstevel@tonic-gate 		/* Phyint is the 1st in the list */
1074*7c478bd9Sstevel@tonic-gate 		phyints = pi->pi_next;
1075*7c478bd9Sstevel@tonic-gate 	} else {
1076*7c478bd9Sstevel@tonic-gate 		pi->pi_prev->pi_next = pi->pi_next;
1077*7c478bd9Sstevel@tonic-gate 	}
1078*7c478bd9Sstevel@tonic-gate 	if (pi->pi_next != NULL)
1079*7c478bd9Sstevel@tonic-gate 		pi->pi_next->pi_prev = pi->pi_prev;
1080*7c478bd9Sstevel@tonic-gate 	pi->pi_next = NULL;
1081*7c478bd9Sstevel@tonic-gate 	pi->pi_prev = NULL;
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate 	free(pi);
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	/* Delete the phyint_group if the last phyint has been deleted */
1086*7c478bd9Sstevel@tonic-gate 	if (pg->pg_phyint == NULL)
1087*7c478bd9Sstevel@tonic-gate 		phyint_group_delete(pg);
1088*7c478bd9Sstevel@tonic-gate }
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate /*
1091*7c478bd9Sstevel@tonic-gate  * Delete (unlink and free), the phyint instance.
1092*7c478bd9Sstevel@tonic-gate  */
1093*7c478bd9Sstevel@tonic-gate void
1094*7c478bd9Sstevel@tonic-gate phyint_inst_delete(struct phyint_instance *pii)
1095*7c478bd9Sstevel@tonic-gate {
1096*7c478bd9Sstevel@tonic-gate 	struct phyint *pi = pii->pii_phyint;
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 	assert(pi != NULL);
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT) {
1101*7c478bd9Sstevel@tonic-gate 		logdebug("phyint_inst_delete(%s %s)\n",
1102*7c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pi->pi_name);
1103*7c478bd9Sstevel@tonic-gate 	}
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	/*
1106*7c478bd9Sstevel@tonic-gate 	 * If the phyint instance has associated probe targets
1107*7c478bd9Sstevel@tonic-gate 	 * delete all the targets
1108*7c478bd9Sstevel@tonic-gate 	 */
1109*7c478bd9Sstevel@tonic-gate 	while (pii->pii_targets != NULL)
1110*7c478bd9Sstevel@tonic-gate 		target_delete(pii->pii_targets);
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	/*
1113*7c478bd9Sstevel@tonic-gate 	 * Delete all the logints associated with this phyint
1114*7c478bd9Sstevel@tonic-gate 	 * instance.
1115*7c478bd9Sstevel@tonic-gate 	 */
1116*7c478bd9Sstevel@tonic-gate 	while (pii->pii_logint != NULL)
1117*7c478bd9Sstevel@tonic-gate 		logint_delete(pii->pii_logint);
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 	/*
1120*7c478bd9Sstevel@tonic-gate 	 * Close the IFF_NOFAILOVER socket used to send probes to targets
1121*7c478bd9Sstevel@tonic-gate 	 * from this phyint.
1122*7c478bd9Sstevel@tonic-gate 	 */
1123*7c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_sock != -1)
1124*7c478bd9Sstevel@tonic-gate 		close_probe_socket(pii, _B_TRUE);
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	/*
1127*7c478bd9Sstevel@tonic-gate 	 * Phyint instance must be in the list of all phyint instances.
1128*7c478bd9Sstevel@tonic-gate 	 * Remove phyint instance from the global list of phyint instances.
1129*7c478bd9Sstevel@tonic-gate 	 */
1130*7c478bd9Sstevel@tonic-gate 	assert(phyint_instances == pii || pii->pii_prev != NULL);
1131*7c478bd9Sstevel@tonic-gate 	if (pii->pii_prev == NULL) {
1132*7c478bd9Sstevel@tonic-gate 		/* Phyint is the 1st in the list */
1133*7c478bd9Sstevel@tonic-gate 		phyint_instances = pii->pii_next;
1134*7c478bd9Sstevel@tonic-gate 	} else {
1135*7c478bd9Sstevel@tonic-gate 		pii->pii_prev->pii_next = pii->pii_next;
1136*7c478bd9Sstevel@tonic-gate 	}
1137*7c478bd9Sstevel@tonic-gate 	if (pii->pii_next != NULL)
1138*7c478bd9Sstevel@tonic-gate 		pii->pii_next->pii_prev = pii->pii_prev;
1139*7c478bd9Sstevel@tonic-gate 	pii->pii_next = NULL;
1140*7c478bd9Sstevel@tonic-gate 	pii->pii_prev = NULL;
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 	/*
1143*7c478bd9Sstevel@tonic-gate 	 * Reset the phyint instance pointer in the phyint.
1144*7c478bd9Sstevel@tonic-gate 	 * If this is the last phyint instance (being deleted) on this
1145*7c478bd9Sstevel@tonic-gate 	 * phyint, then delete the phyint.
1146*7c478bd9Sstevel@tonic-gate 	 */
1147*7c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET)
1148*7c478bd9Sstevel@tonic-gate 		pi->pi_v4 = NULL;
1149*7c478bd9Sstevel@tonic-gate 	else
1150*7c478bd9Sstevel@tonic-gate 		pi->pi_v6 = NULL;
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate 	if (pi->pi_v4 == NULL && pi->pi_v6 == NULL)
1153*7c478bd9Sstevel@tonic-gate 		phyint_delete(pi);
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	free(pii);
1156*7c478bd9Sstevel@tonic-gate }
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate static void
1159*7c478bd9Sstevel@tonic-gate phyint_inst_print(struct phyint_instance *pii)
1160*7c478bd9Sstevel@tonic-gate {
1161*7c478bd9Sstevel@tonic-gate 	struct logint *li;
1162*7c478bd9Sstevel@tonic-gate 	struct target *tg;
1163*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1164*7c478bd9Sstevel@tonic-gate 	int most_recent;
1165*7c478bd9Sstevel@tonic-gate 	int i;
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	if (pii->pii_phyint == NULL) {
1168*7c478bd9Sstevel@tonic-gate 		logdebug("pii->pi_phyint NULL can't print\n");
1169*7c478bd9Sstevel@tonic-gate 		return;
1170*7c478bd9Sstevel@tonic-gate 	}
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	logdebug("\nPhyint instance: %s %s index %u state %x flags %llx	 "
1173*7c478bd9Sstevel@tonic-gate 	    "sock %x in_use %d empty %x full %x\n",
1174*7c478bd9Sstevel@tonic-gate 	    AF_STR(pii->pii_af), pii->pii_name, pii->pii_ifindex,
1175*7c478bd9Sstevel@tonic-gate 	    pii->pii_state, pii->pii_phyint->pi_flags, pii->pii_probe_sock,
1176*7c478bd9Sstevel@tonic-gate 	    pii->pii_in_use, pii->pii_phyint->pi_empty,
1177*7c478bd9Sstevel@tonic-gate 	    pii->pii_phyint->pi_full);
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 	for (li = pii->pii_logint; li != NULL; li = li->li_next)
1180*7c478bd9Sstevel@tonic-gate 		logint_print(li);
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate 	logdebug("\n");
1183*7c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next)
1184*7c478bd9Sstevel@tonic-gate 		target_print(tg);
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate 	if (pii->pii_targets == NULL)
1187*7c478bd9Sstevel@tonic-gate 		logdebug("pi_targets NULL\n");
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate 	if (pii->pii_target_next != NULL) {
1190*7c478bd9Sstevel@tonic-gate 		logdebug("pi_target_next %s %s\n", AF_STR(pii->pii_af),
1191*7c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, pii->pii_target_next->tg_address,
1192*7c478bd9Sstevel@tonic-gate 			abuf, sizeof (abuf)));
1193*7c478bd9Sstevel@tonic-gate 	} else {
1194*7c478bd9Sstevel@tonic-gate 		logdebug("pi_target_next NULL\n");
1195*7c478bd9Sstevel@tonic-gate 	}
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	if (pii->pii_rtt_target_next != NULL) {
1198*7c478bd9Sstevel@tonic-gate 		logdebug("pi_rtt_target_next %s %s\n", AF_STR(pii->pii_af),
1199*7c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, pii->pii_rtt_target_next->tg_address,
1200*7c478bd9Sstevel@tonic-gate 			abuf, sizeof (abuf)));
1201*7c478bd9Sstevel@tonic-gate 	} else {
1202*7c478bd9Sstevel@tonic-gate 		logdebug("pi_rtt_target_next NULL\n");
1203*7c478bd9Sstevel@tonic-gate 	}
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate 	if (pii->pii_targets != NULL) {
1206*7c478bd9Sstevel@tonic-gate 		most_recent = PROBE_INDEX_PREV(pii->pii_probe_next);
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 		i = most_recent;
1209*7c478bd9Sstevel@tonic-gate 		do {
1210*7c478bd9Sstevel@tonic-gate 			if (pii->pii_probes[i].pr_target != NULL) {
1211*7c478bd9Sstevel@tonic-gate 				logdebug("#%d target %s ", i,
1212*7c478bd9Sstevel@tonic-gate 				    pr_addr(pii->pii_af,
1213*7c478bd9Sstevel@tonic-gate 				    pii->pii_probes[i].pr_target->tg_address,
1214*7c478bd9Sstevel@tonic-gate 				    abuf, sizeof (abuf)));
1215*7c478bd9Sstevel@tonic-gate 			} else {
1216*7c478bd9Sstevel@tonic-gate 				logdebug("#%d target NULL ", i);
1217*7c478bd9Sstevel@tonic-gate 			}
1218*7c478bd9Sstevel@tonic-gate 			logdebug("time_sent %u status %d time_ack/lost %u\n",
1219*7c478bd9Sstevel@tonic-gate 			    pii->pii_probes[i].pr_time_sent,
1220*7c478bd9Sstevel@tonic-gate 			    pii->pii_probes[i].pr_status,
1221*7c478bd9Sstevel@tonic-gate 			    pii->pii_probes[i].pr_time_lost);
1222*7c478bd9Sstevel@tonic-gate 			i = PROBE_INDEX_PREV(i);
1223*7c478bd9Sstevel@tonic-gate 		} while (i != most_recent);
1224*7c478bd9Sstevel@tonic-gate 	}
1225*7c478bd9Sstevel@tonic-gate }
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate /*
1228*7c478bd9Sstevel@tonic-gate  * Lookup a logint based on the logical interface name, on the given
1229*7c478bd9Sstevel@tonic-gate  * phyint instance.
1230*7c478bd9Sstevel@tonic-gate  */
1231*7c478bd9Sstevel@tonic-gate static struct logint *
1232*7c478bd9Sstevel@tonic-gate logint_lookup(struct phyint_instance *pii, char *name)
1233*7c478bd9Sstevel@tonic-gate {
1234*7c478bd9Sstevel@tonic-gate 	struct logint *li;
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
1237*7c478bd9Sstevel@tonic-gate 		logdebug("logint_lookup(%s, %s)\n",
1238*7c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), name);
1239*7c478bd9Sstevel@tonic-gate 	}
1240*7c478bd9Sstevel@tonic-gate 
1241*7c478bd9Sstevel@tonic-gate 	for (li = pii->pii_logint; li != NULL; li = li->li_next) {
1242*7c478bd9Sstevel@tonic-gate 		if (strncmp(name, li->li_name, sizeof (li->li_name)) == 0)
1243*7c478bd9Sstevel@tonic-gate 			break;
1244*7c478bd9Sstevel@tonic-gate 	}
1245*7c478bd9Sstevel@tonic-gate 	return (li);
1246*7c478bd9Sstevel@tonic-gate }
1247*7c478bd9Sstevel@tonic-gate 
1248*7c478bd9Sstevel@tonic-gate /*
1249*7c478bd9Sstevel@tonic-gate  * Insert a logint at the head of the list of logints of the given
1250*7c478bd9Sstevel@tonic-gate  * phyint instance
1251*7c478bd9Sstevel@tonic-gate  */
1252*7c478bd9Sstevel@tonic-gate static void
1253*7c478bd9Sstevel@tonic-gate logint_insert(struct phyint_instance *pii, struct logint *li)
1254*7c478bd9Sstevel@tonic-gate {
1255*7c478bd9Sstevel@tonic-gate 	li->li_next = pii->pii_logint;
1256*7c478bd9Sstevel@tonic-gate 	li->li_prev = NULL;
1257*7c478bd9Sstevel@tonic-gate 	if (pii->pii_logint != NULL)
1258*7c478bd9Sstevel@tonic-gate 		pii->pii_logint->li_prev = li;
1259*7c478bd9Sstevel@tonic-gate 	pii->pii_logint = li;
1260*7c478bd9Sstevel@tonic-gate 	li->li_phyint_inst = pii;
1261*7c478bd9Sstevel@tonic-gate }
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate /*
1264*7c478bd9Sstevel@tonic-gate  * Create a new named logint, on the specified phyint instance.
1265*7c478bd9Sstevel@tonic-gate  */
1266*7c478bd9Sstevel@tonic-gate static struct logint *
1267*7c478bd9Sstevel@tonic-gate logint_create(struct phyint_instance *pii, char *name)
1268*7c478bd9Sstevel@tonic-gate {
1269*7c478bd9Sstevel@tonic-gate 	struct logint *li;
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
1272*7c478bd9Sstevel@tonic-gate 		logdebug("logint_create(%s %s %s)\n",
1273*7c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name, name);
1274*7c478bd9Sstevel@tonic-gate 	}
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate 	li = calloc(1, sizeof (struct logint));
1277*7c478bd9Sstevel@tonic-gate 	if (li == NULL) {
1278*7c478bd9Sstevel@tonic-gate 		logperror("logint_create: calloc");
1279*7c478bd9Sstevel@tonic-gate 		return (NULL);
1280*7c478bd9Sstevel@tonic-gate 	}
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate 	(void) strncpy(li->li_name, name, sizeof (li->li_name));
1283*7c478bd9Sstevel@tonic-gate 	li->li_name[sizeof (li->li_name) - 1] = '\0';
1284*7c478bd9Sstevel@tonic-gate 	logint_insert(pii, li);
1285*7c478bd9Sstevel@tonic-gate 	return (li);
1286*7c478bd9Sstevel@tonic-gate }
1287*7c478bd9Sstevel@tonic-gate 
1288*7c478bd9Sstevel@tonic-gate /*
1289*7c478bd9Sstevel@tonic-gate  * Initialize the logint based on the data returned by the kernel.
1290*7c478bd9Sstevel@tonic-gate  */
1291*7c478bd9Sstevel@tonic-gate void
1292*7c478bd9Sstevel@tonic-gate logint_init_from_k(struct phyint_instance *pii, char *li_name)
1293*7c478bd9Sstevel@tonic-gate {
1294*7c478bd9Sstevel@tonic-gate 	int	ifsock;
1295*7c478bd9Sstevel@tonic-gate 	uint64_t flags;
1296*7c478bd9Sstevel@tonic-gate 	uint64_t saved_flags;
1297*7c478bd9Sstevel@tonic-gate 	struct	logint	*li;
1298*7c478bd9Sstevel@tonic-gate 	struct lifreq	lifr;
1299*7c478bd9Sstevel@tonic-gate 	struct in6_addr	test_subnet;
1300*7c478bd9Sstevel@tonic-gate 	struct in6_addr	test_subnet_mask;
1301*7c478bd9Sstevel@tonic-gate 	struct in6_addr	testaddr;
1302*7c478bd9Sstevel@tonic-gate 	int	test_subnet_len;
1303*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
1304*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin;
1305*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1306*7c478bd9Sstevel@tonic-gate 	boolean_t  ptp = _B_FALSE;
1307*7c478bd9Sstevel@tonic-gate 	struct in6_addr tgaddr;
1308*7c478bd9Sstevel@tonic-gate 
1309*7c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
1310*7c478bd9Sstevel@tonic-gate 		logdebug("logint_init_from_k(%s %s)\n",
1311*7c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), li_name);
1312*7c478bd9Sstevel@tonic-gate 	}
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate 	/* Get the socket for doing ioctls */
1315*7c478bd9Sstevel@tonic-gate 	ifsock = (pii->pii_af == AF_INET) ? ifsock_v4 : ifsock_v6;
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate 	/*
1318*7c478bd9Sstevel@tonic-gate 	 * Get the flags from the kernel. Also serves as a check whether
1319*7c478bd9Sstevel@tonic-gate 	 * the logical still exists. If it doesn't exist, no need to proceed
1320*7c478bd9Sstevel@tonic-gate 	 * any further. li_in_use will make the caller clean up the logint
1321*7c478bd9Sstevel@tonic-gate 	 */
1322*7c478bd9Sstevel@tonic-gate 	(void) strncpy(lifr.lifr_name, li_name, sizeof (lifr.lifr_name));
1323*7c478bd9Sstevel@tonic-gate 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1324*7c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
1325*7c478bd9Sstevel@tonic-gate 		/* Interface may have vanished */
1326*7c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
1327*7c478bd9Sstevel@tonic-gate 			logperror_pii(pii, "logint_init_from_k: "
1328*7c478bd9Sstevel@tonic-gate 			    "ioctl (get flags)");
1329*7c478bd9Sstevel@tonic-gate 		}
1330*7c478bd9Sstevel@tonic-gate 		return;
1331*7c478bd9Sstevel@tonic-gate 	}
1332*7c478bd9Sstevel@tonic-gate 
1333*7c478bd9Sstevel@tonic-gate 	flags = lifr.lifr_flags;
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate 	/*
1336*7c478bd9Sstevel@tonic-gate 	 * Verified the logint exists. Now lookup the logint in our tables.
1337*7c478bd9Sstevel@tonic-gate 	 * If it does not exist, create a new logint.
1338*7c478bd9Sstevel@tonic-gate 	 */
1339*7c478bd9Sstevel@tonic-gate 	li = logint_lookup(pii, li_name);
1340*7c478bd9Sstevel@tonic-gate 	if (li == NULL) {
1341*7c478bd9Sstevel@tonic-gate 		li = logint_create(pii, li_name);
1342*7c478bd9Sstevel@tonic-gate 		if (li == NULL) {
1343*7c478bd9Sstevel@tonic-gate 			/*
1344*7c478bd9Sstevel@tonic-gate 			 * Pretend the interface does not exist
1345*7c478bd9Sstevel@tonic-gate 			 * in the kernel
1346*7c478bd9Sstevel@tonic-gate 			 */
1347*7c478bd9Sstevel@tonic-gate 			return;
1348*7c478bd9Sstevel@tonic-gate 		}
1349*7c478bd9Sstevel@tonic-gate 	}
1350*7c478bd9Sstevel@tonic-gate 
1351*7c478bd9Sstevel@tonic-gate 	/*
1352*7c478bd9Sstevel@tonic-gate 	 * Update li->li_flags with the new flags, after saving the old
1353*7c478bd9Sstevel@tonic-gate 	 * value. This is used later to check what flags has changed and
1354*7c478bd9Sstevel@tonic-gate 	 * take any action
1355*7c478bd9Sstevel@tonic-gate 	 */
1356*7c478bd9Sstevel@tonic-gate 	saved_flags = li->li_flags;
1357*7c478bd9Sstevel@tonic-gate 	li->li_flags = flags;
1358*7c478bd9Sstevel@tonic-gate 
1359*7c478bd9Sstevel@tonic-gate 	/*
1360*7c478bd9Sstevel@tonic-gate 	 * Get the address, prefix, prefixlength and update the logint.
1361*7c478bd9Sstevel@tonic-gate 	 * Check if anything has changed. If the logint used for the
1362*7c478bd9Sstevel@tonic-gate 	 * test address has changed, take suitable action.
1363*7c478bd9Sstevel@tonic-gate 	 */
1364*7c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFADDR, (char *)&lifr) < 0) {
1365*7c478bd9Sstevel@tonic-gate 		/* Interface may have vanished */
1366*7c478bd9Sstevel@tonic-gate 		if (errno != ENXIO) {
1367*7c478bd9Sstevel@tonic-gate 			logperror_li(li, "logint_init_from_k: (get addr)");
1368*7c478bd9Sstevel@tonic-gate 		}
1369*7c478bd9Sstevel@tonic-gate 		goto error;
1370*7c478bd9Sstevel@tonic-gate 	}
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET) {
1373*7c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
1374*7c478bd9Sstevel@tonic-gate 		IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &testaddr);
1375*7c478bd9Sstevel@tonic-gate 	} else {
1376*7c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1377*7c478bd9Sstevel@tonic-gate 		testaddr = sin6->sin6_addr;
1378*7c478bd9Sstevel@tonic-gate 	}
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 	if (pii->pii_phyint->pi_flags & IFF_POINTOPOINT) {
1381*7c478bd9Sstevel@tonic-gate 		ptp = _B_TRUE;
1382*7c478bd9Sstevel@tonic-gate 		if (ioctl(ifsock, SIOCGLIFDSTADDR, (char *)&lifr) < 0) {
1383*7c478bd9Sstevel@tonic-gate 			if (errno != ENXIO) {
1384*7c478bd9Sstevel@tonic-gate 				logperror_li(li, "logint_init_from_k:"
1385*7c478bd9Sstevel@tonic-gate 				    " (get dstaddr)");
1386*7c478bd9Sstevel@tonic-gate 			}
1387*7c478bd9Sstevel@tonic-gate 			goto error;
1388*7c478bd9Sstevel@tonic-gate 		}
1389*7c478bd9Sstevel@tonic-gate 		if (pii->pii_af == AF_INET) {
1390*7c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&lifr.lifr_addr;
1391*7c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &tgaddr);
1392*7c478bd9Sstevel@tonic-gate 		} else {
1393*7c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1394*7c478bd9Sstevel@tonic-gate 			tgaddr = sin6->sin6_addr;
1395*7c478bd9Sstevel@tonic-gate 		}
1396*7c478bd9Sstevel@tonic-gate 	} else {
1397*7c478bd9Sstevel@tonic-gate 		if (ioctl(ifsock, SIOCGLIFSUBNET, (char *)&lifr) < 0) {
1398*7c478bd9Sstevel@tonic-gate 			/* Interface may have vanished */
1399*7c478bd9Sstevel@tonic-gate 			if (errno != ENXIO) {
1400*7c478bd9Sstevel@tonic-gate 				logperror_li(li, "logint_init_from_k:"
1401*7c478bd9Sstevel@tonic-gate 				    " (get subnet)");
1402*7c478bd9Sstevel@tonic-gate 			}
1403*7c478bd9Sstevel@tonic-gate 			goto error;
1404*7c478bd9Sstevel@tonic-gate 		}
1405*7c478bd9Sstevel@tonic-gate 		if (lifr.lifr_subnet.ss_family == AF_INET6) {
1406*7c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)&lifr.lifr_subnet;
1407*7c478bd9Sstevel@tonic-gate 			test_subnet = sin6->sin6_addr;
1408*7c478bd9Sstevel@tonic-gate 			test_subnet_len = lifr.lifr_addrlen;
1409*7c478bd9Sstevel@tonic-gate 		} else {
1410*7c478bd9Sstevel@tonic-gate 			sin = (struct sockaddr_in *)&lifr.lifr_subnet;
1411*7c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &test_subnet);
1412*7c478bd9Sstevel@tonic-gate 			test_subnet_len = lifr.lifr_addrlen +
1413*7c478bd9Sstevel@tonic-gate 			    (IPV6_ABITS - IP_ABITS);
1414*7c478bd9Sstevel@tonic-gate 		}
1415*7c478bd9Sstevel@tonic-gate 		(void) ip_index_to_mask_v6(test_subnet_len, &test_subnet_mask);
1416*7c478bd9Sstevel@tonic-gate 	}
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate 	/*
1419*7c478bd9Sstevel@tonic-gate 	 * Also record the OINDEX for completeness. This information is
1420*7c478bd9Sstevel@tonic-gate 	 * not used.
1421*7c478bd9Sstevel@tonic-gate 	 */
1422*7c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock, SIOCGLIFOINDEX, (char *)&lifr) < 0) {
1423*7c478bd9Sstevel@tonic-gate 		if (errno != ENXIO)  {
1424*7c478bd9Sstevel@tonic-gate 			logperror_li(li, "logint_init_from_k:"
1425*7c478bd9Sstevel@tonic-gate 			    " (get lifoindex)");
1426*7c478bd9Sstevel@tonic-gate 		}
1427*7c478bd9Sstevel@tonic-gate 		goto error;
1428*7c478bd9Sstevel@tonic-gate 	}
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate 	/*
1431*7c478bd9Sstevel@tonic-gate 	 * If this is the logint corresponding to the test address used for
1432*7c478bd9Sstevel@tonic-gate 	 * sending probes, then if anything significant has changed we need to
1433*7c478bd9Sstevel@tonic-gate 	 * determine the test address again.  We ignore changes to the
1434*7c478bd9Sstevel@tonic-gate 	 * IFF_FAILED and IFF_RUNNING flags since those happen as a matter of
1435*7c478bd9Sstevel@tonic-gate 	 * course.
1436*7c478bd9Sstevel@tonic-gate 	 */
1437*7c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_logint == li) {
1438*7c478bd9Sstevel@tonic-gate 		if (((li->li_flags ^ saved_flags) &
1439*7c478bd9Sstevel@tonic-gate 		    ~(IFF_FAILED | IFF_RUNNING)) != 0 ||
1440*7c478bd9Sstevel@tonic-gate 		    !IN6_ARE_ADDR_EQUAL(&testaddr, &li->li_addr) ||
1441*7c478bd9Sstevel@tonic-gate 		    (!ptp && !IN6_ARE_ADDR_EQUAL(&test_subnet,
1442*7c478bd9Sstevel@tonic-gate 			&li->li_subnet)) ||
1443*7c478bd9Sstevel@tonic-gate 		    (!ptp && test_subnet_len != li->li_subnet_len) ||
1444*7c478bd9Sstevel@tonic-gate 		    (ptp && !IN6_ARE_ADDR_EQUAL(&tgaddr, &li->li_dstaddr))) {
1445*7c478bd9Sstevel@tonic-gate 			/*
1446*7c478bd9Sstevel@tonic-gate 			 * Something significant that affects the testaddress
1447*7c478bd9Sstevel@tonic-gate 			 * has changed. Redo the testaddress selection later on
1448*7c478bd9Sstevel@tonic-gate 			 * in select_test_ifs(). For now do the cleanup and
1449*7c478bd9Sstevel@tonic-gate 			 * set pii_probe_logint to NULL.
1450*7c478bd9Sstevel@tonic-gate 			 */
1451*7c478bd9Sstevel@tonic-gate 			if (pii->pii_probe_sock != -1)
1452*7c478bd9Sstevel@tonic-gate 				close_probe_socket(pii, _B_TRUE);
1453*7c478bd9Sstevel@tonic-gate 			pii->pii_probe_logint = NULL;
1454*7c478bd9Sstevel@tonic-gate 		}
1455*7c478bd9Sstevel@tonic-gate 	}
1456*7c478bd9Sstevel@tonic-gate 
1457*7c478bd9Sstevel@tonic-gate 
1458*7c478bd9Sstevel@tonic-gate 	/* Update the logint with the values obtained from the kernel.	*/
1459*7c478bd9Sstevel@tonic-gate 	li->li_addr = testaddr;
1460*7c478bd9Sstevel@tonic-gate 	li->li_in_use = 1;
1461*7c478bd9Sstevel@tonic-gate 	li->li_oifindex = lifr.lifr_index;
1462*7c478bd9Sstevel@tonic-gate 	if (ptp) {
1463*7c478bd9Sstevel@tonic-gate 		li->li_dstaddr = tgaddr;
1464*7c478bd9Sstevel@tonic-gate 		li->li_subnet_len = (pii->pii_af == AF_INET) ?
1465*7c478bd9Sstevel@tonic-gate 		    IP_ABITS : IPV6_ABITS;
1466*7c478bd9Sstevel@tonic-gate 	} else {
1467*7c478bd9Sstevel@tonic-gate 		li->li_subnet = test_subnet;
1468*7c478bd9Sstevel@tonic-gate 		li->li_subnet_len = test_subnet_len;
1469*7c478bd9Sstevel@tonic-gate 	}
1470*7c478bd9Sstevel@tonic-gate 
1471*7c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT)
1472*7c478bd9Sstevel@tonic-gate 		logint_print(li);
1473*7c478bd9Sstevel@tonic-gate 
1474*7c478bd9Sstevel@tonic-gate 	return;
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate error:
1477*7c478bd9Sstevel@tonic-gate 	logerr("logint_init_from_k: IGNORED %s %s %s addr %s\n",
1478*7c478bd9Sstevel@tonic-gate 	    AF_STR(pii->pii_af), pii->pii_name, li->li_name,
1479*7c478bd9Sstevel@tonic-gate 	    pr_addr(pii->pii_af, testaddr, abuf, sizeof (abuf)));
1480*7c478bd9Sstevel@tonic-gate 	logint_delete(li);
1481*7c478bd9Sstevel@tonic-gate }
1482*7c478bd9Sstevel@tonic-gate 
1483*7c478bd9Sstevel@tonic-gate /*
1484*7c478bd9Sstevel@tonic-gate  * Delete (unlink and free) a logint.
1485*7c478bd9Sstevel@tonic-gate  */
1486*7c478bd9Sstevel@tonic-gate void
1487*7c478bd9Sstevel@tonic-gate logint_delete(struct logint *li)
1488*7c478bd9Sstevel@tonic-gate {
1489*7c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate 	pii = li->li_phyint_inst;
1492*7c478bd9Sstevel@tonic-gate 	assert(pii != NULL);
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate 	if (debug & D_LOGINT) {
1495*7c478bd9Sstevel@tonic-gate 		int af;
1496*7c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 		af = pii->pii_af;
1499*7c478bd9Sstevel@tonic-gate 		logdebug("logint_delete(%s %s %s/%u)\n",
1500*7c478bd9Sstevel@tonic-gate 		    AF_STR(af), li->li_name,
1501*7c478bd9Sstevel@tonic-gate 		    pr_addr(af, li->li_addr, abuf, sizeof (abuf)),
1502*7c478bd9Sstevel@tonic-gate 		    li->li_subnet_len);
1503*7c478bd9Sstevel@tonic-gate 	}
1504*7c478bd9Sstevel@tonic-gate 
1505*7c478bd9Sstevel@tonic-gate 	/* logint must be in the list of logints */
1506*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_logint == li || li->li_prev != NULL);
1507*7c478bd9Sstevel@tonic-gate 
1508*7c478bd9Sstevel@tonic-gate 	/* Remove the logint from the list of logints  */
1509*7c478bd9Sstevel@tonic-gate 	if (li->li_prev == NULL) {
1510*7c478bd9Sstevel@tonic-gate 		/* logint is the 1st in the list */
1511*7c478bd9Sstevel@tonic-gate 		pii->pii_logint = li->li_next;
1512*7c478bd9Sstevel@tonic-gate 	} else {
1513*7c478bd9Sstevel@tonic-gate 		li->li_prev->li_next = li->li_next;
1514*7c478bd9Sstevel@tonic-gate 	}
1515*7c478bd9Sstevel@tonic-gate 	if (li->li_next != NULL)
1516*7c478bd9Sstevel@tonic-gate 		li->li_next->li_prev = li->li_prev;
1517*7c478bd9Sstevel@tonic-gate 	li->li_next = NULL;
1518*7c478bd9Sstevel@tonic-gate 	li->li_prev = NULL;
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate 	/*
1521*7c478bd9Sstevel@tonic-gate 	 * If this logint corresponds to the IFF_NOFAILOVER testaddress of
1522*7c478bd9Sstevel@tonic-gate 	 * this phyint, then close the associated socket, if it exists
1523*7c478bd9Sstevel@tonic-gate 	 */
1524*7c478bd9Sstevel@tonic-gate 	if (pii->pii_probe_logint == li) {
1525*7c478bd9Sstevel@tonic-gate 		if (pii->pii_probe_sock != -1)
1526*7c478bd9Sstevel@tonic-gate 			close_probe_socket(pii, _B_TRUE);
1527*7c478bd9Sstevel@tonic-gate 		pii->pii_probe_logint = NULL;
1528*7c478bd9Sstevel@tonic-gate 	}
1529*7c478bd9Sstevel@tonic-gate 
1530*7c478bd9Sstevel@tonic-gate 	free(li);
1531*7c478bd9Sstevel@tonic-gate }
1532*7c478bd9Sstevel@tonic-gate 
1533*7c478bd9Sstevel@tonic-gate static void
1534*7c478bd9Sstevel@tonic-gate logint_print(struct logint *li)
1535*7c478bd9Sstevel@tonic-gate {
1536*7c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
1537*7c478bd9Sstevel@tonic-gate 	int af;
1538*7c478bd9Sstevel@tonic-gate 
1539*7c478bd9Sstevel@tonic-gate 	af = li->li_phyint_inst->pii_af;
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate 	logdebug("logint: %s %s addr %s/%u", AF_STR(af), li->li_name,
1542*7c478bd9Sstevel@tonic-gate 	    pr_addr(af, li->li_addr, abuf, sizeof (abuf)), li->li_subnet_len);
1543*7c478bd9Sstevel@tonic-gate 
1544*7c478bd9Sstevel@tonic-gate 	logdebug("\tFlags: %llx in_use %d oifindex %d\n",
1545*7c478bd9Sstevel@tonic-gate 	    li->li_flags, li->li_in_use, li->li_oifindex);
1546*7c478bd9Sstevel@tonic-gate }
1547*7c478bd9Sstevel@tonic-gate 
1548*7c478bd9Sstevel@tonic-gate char *
1549*7c478bd9Sstevel@tonic-gate pr_addr(int af, struct in6_addr addr, char *abuf, int len)
1550*7c478bd9Sstevel@tonic-gate {
1551*7c478bd9Sstevel@tonic-gate 	struct in_addr	addr_v4;
1552*7c478bd9Sstevel@tonic-gate 
1553*7c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
1554*7c478bd9Sstevel@tonic-gate 		IN6_V4MAPPED_TO_INADDR(&addr, &addr_v4);
1555*7c478bd9Sstevel@tonic-gate 		(void) inet_ntop(AF_INET, (void *)&addr_v4, abuf, len);
1556*7c478bd9Sstevel@tonic-gate 	} else {
1557*7c478bd9Sstevel@tonic-gate 		(void) inet_ntop(AF_INET6, (void *)&addr, abuf, len);
1558*7c478bd9Sstevel@tonic-gate 	}
1559*7c478bd9Sstevel@tonic-gate 	return (abuf);
1560*7c478bd9Sstevel@tonic-gate }
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate /* Lookup target on its address */
1563*7c478bd9Sstevel@tonic-gate struct target *
1564*7c478bd9Sstevel@tonic-gate target_lookup(struct phyint_instance *pii, struct in6_addr addr)
1565*7c478bd9Sstevel@tonic-gate {
1566*7c478bd9Sstevel@tonic-gate 	struct target *tg;
1567*7c478bd9Sstevel@tonic-gate 
1568*7c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET) {
1569*7c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
1570*7c478bd9Sstevel@tonic-gate 
1571*7c478bd9Sstevel@tonic-gate 		logdebug("target_lookup(%s %s): addr %s\n",
1572*7c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name,
1573*7c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, addr, abuf, sizeof (abuf)));
1574*7c478bd9Sstevel@tonic-gate 	}
1575*7c478bd9Sstevel@tonic-gate 
1576*7c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) {
1577*7c478bd9Sstevel@tonic-gate 		if (IN6_ARE_ADDR_EQUAL(&tg->tg_address, &addr))
1578*7c478bd9Sstevel@tonic-gate 			break;
1579*7c478bd9Sstevel@tonic-gate 	}
1580*7c478bd9Sstevel@tonic-gate 	return (tg);
1581*7c478bd9Sstevel@tonic-gate }
1582*7c478bd9Sstevel@tonic-gate 
1583*7c478bd9Sstevel@tonic-gate /*
1584*7c478bd9Sstevel@tonic-gate  * Find and return the next active target, for the next probe.
1585*7c478bd9Sstevel@tonic-gate  * If no active targets are available, return NULL.
1586*7c478bd9Sstevel@tonic-gate  */
1587*7c478bd9Sstevel@tonic-gate struct target *
1588*7c478bd9Sstevel@tonic-gate target_next(struct target *tg)
1589*7c478bd9Sstevel@tonic-gate {
1590*7c478bd9Sstevel@tonic-gate 	struct	phyint_instance	*pii = tg->tg_phyint_inst;
1591*7c478bd9Sstevel@tonic-gate 	struct	target	*marker = tg;
1592*7c478bd9Sstevel@tonic-gate 	hrtime_t now;
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 	now = gethrtime();
1595*7c478bd9Sstevel@tonic-gate 
1596*7c478bd9Sstevel@tonic-gate 	/*
1597*7c478bd9Sstevel@tonic-gate 	 * Target must be in the list of targets for this phyint
1598*7c478bd9Sstevel@tonic-gate 	 * instance.
1599*7c478bd9Sstevel@tonic-gate 	 */
1600*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets == tg || tg->tg_prev != NULL);
1601*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets != NULL);
1602*7c478bd9Sstevel@tonic-gate 
1603*7c478bd9Sstevel@tonic-gate 	/* Return the next active target */
1604*7c478bd9Sstevel@tonic-gate 	do {
1605*7c478bd9Sstevel@tonic-gate 		/*
1606*7c478bd9Sstevel@tonic-gate 		 * Go to the next target. If we hit the end,
1607*7c478bd9Sstevel@tonic-gate 		 * reset the ptr to the head
1608*7c478bd9Sstevel@tonic-gate 		 */
1609*7c478bd9Sstevel@tonic-gate 		tg = tg->tg_next;
1610*7c478bd9Sstevel@tonic-gate 		if (tg == NULL)
1611*7c478bd9Sstevel@tonic-gate 			tg = pii->pii_targets;
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
1614*7c478bd9Sstevel@tonic-gate 
1615*7c478bd9Sstevel@tonic-gate 		switch (tg->tg_status) {
1616*7c478bd9Sstevel@tonic-gate 		case TG_ACTIVE:
1617*7c478bd9Sstevel@tonic-gate 			return (tg);
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate 		case TG_UNUSED:
1620*7c478bd9Sstevel@tonic-gate 			assert(pii->pii_targets_are_routers);
1621*7c478bd9Sstevel@tonic-gate 			if (pii->pii_ntargets < MAX_PROBE_TARGETS) {
1622*7c478bd9Sstevel@tonic-gate 				/*
1623*7c478bd9Sstevel@tonic-gate 				 * Bubble up the unused target to active
1624*7c478bd9Sstevel@tonic-gate 				 */
1625*7c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_ACTIVE;
1626*7c478bd9Sstevel@tonic-gate 				pii->pii_ntargets++;
1627*7c478bd9Sstevel@tonic-gate 				return (tg);
1628*7c478bd9Sstevel@tonic-gate 			}
1629*7c478bd9Sstevel@tonic-gate 			break;
1630*7c478bd9Sstevel@tonic-gate 
1631*7c478bd9Sstevel@tonic-gate 		case TG_SLOW:
1632*7c478bd9Sstevel@tonic-gate 			assert(pii->pii_targets_are_routers);
1633*7c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
1634*7c478bd9Sstevel@tonic-gate 				/*
1635*7c478bd9Sstevel@tonic-gate 				 * Bubble up the slow target to unused
1636*7c478bd9Sstevel@tonic-gate 				 */
1637*7c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_UNUSED;
1638*7c478bd9Sstevel@tonic-gate 			}
1639*7c478bd9Sstevel@tonic-gate 			break;
1640*7c478bd9Sstevel@tonic-gate 
1641*7c478bd9Sstevel@tonic-gate 		case TG_DEAD:
1642*7c478bd9Sstevel@tonic-gate 			assert(pii->pii_targets_are_routers);
1643*7c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
1644*7c478bd9Sstevel@tonic-gate 				/*
1645*7c478bd9Sstevel@tonic-gate 				 * Bubble up the dead target to slow
1646*7c478bd9Sstevel@tonic-gate 				 */
1647*7c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_SLOW;
1648*7c478bd9Sstevel@tonic-gate 				tg->tg_latime = now;
1649*7c478bd9Sstevel@tonic-gate 			}
1650*7c478bd9Sstevel@tonic-gate 			break;
1651*7c478bd9Sstevel@tonic-gate 		}
1652*7c478bd9Sstevel@tonic-gate 
1653*7c478bd9Sstevel@tonic-gate 	} while (tg != marker);
1654*7c478bd9Sstevel@tonic-gate 
1655*7c478bd9Sstevel@tonic-gate 	return (NULL);
1656*7c478bd9Sstevel@tonic-gate }
1657*7c478bd9Sstevel@tonic-gate 
1658*7c478bd9Sstevel@tonic-gate /*
1659*7c478bd9Sstevel@tonic-gate  * Select the best available target, that is not already TG_ACTIVE,
1660*7c478bd9Sstevel@tonic-gate  * for the caller. The caller will determine whether it wants to
1661*7c478bd9Sstevel@tonic-gate  * make the returned target TG_ACTIVE.
1662*7c478bd9Sstevel@tonic-gate  * The selection order is as follows.
1663*7c478bd9Sstevel@tonic-gate  * 1. pick a TG_UNSED target, if it exists.
1664*7c478bd9Sstevel@tonic-gate  * 2. else pick a TG_SLOW target that has recovered, if it exists
1665*7c478bd9Sstevel@tonic-gate  * 3. else pick any TG_SLOW target, if it exists
1666*7c478bd9Sstevel@tonic-gate  * 4. else pick a TG_DEAD target that has recovered, if it exists
1667*7c478bd9Sstevel@tonic-gate  * 5. else pick any TG_DEAD target, if it exists
1668*7c478bd9Sstevel@tonic-gate  * 6. else return null
1669*7c478bd9Sstevel@tonic-gate  */
1670*7c478bd9Sstevel@tonic-gate static struct target *
1671*7c478bd9Sstevel@tonic-gate target_select_best(struct phyint_instance *pii)
1672*7c478bd9Sstevel@tonic-gate {
1673*7c478bd9Sstevel@tonic-gate 	struct target *tg;
1674*7c478bd9Sstevel@tonic-gate 	struct target *slow = NULL;
1675*7c478bd9Sstevel@tonic-gate 	struct target *dead = NULL;
1676*7c478bd9Sstevel@tonic-gate 	struct target *slow_recovered = NULL;
1677*7c478bd9Sstevel@tonic-gate 	struct target *dead_recovered = NULL;
1678*7c478bd9Sstevel@tonic-gate 	hrtime_t now;
1679*7c478bd9Sstevel@tonic-gate 
1680*7c478bd9Sstevel@tonic-gate 	now = gethrtime();
1681*7c478bd9Sstevel@tonic-gate 
1682*7c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) {
1683*7c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
1684*7c478bd9Sstevel@tonic-gate 
1685*7c478bd9Sstevel@tonic-gate 		switch (tg->tg_status) {
1686*7c478bd9Sstevel@tonic-gate 		case TG_UNUSED:
1687*7c478bd9Sstevel@tonic-gate 			return (tg);
1688*7c478bd9Sstevel@tonic-gate 
1689*7c478bd9Sstevel@tonic-gate 		case TG_SLOW:
1690*7c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
1691*7c478bd9Sstevel@tonic-gate 				slow_recovered = tg;
1692*7c478bd9Sstevel@tonic-gate 				/*
1693*7c478bd9Sstevel@tonic-gate 				 * Promote the slow_recoverd to unused
1694*7c478bd9Sstevel@tonic-gate 				 */
1695*7c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_UNUSED;
1696*7c478bd9Sstevel@tonic-gate 			} else {
1697*7c478bd9Sstevel@tonic-gate 				slow = tg;
1698*7c478bd9Sstevel@tonic-gate 			}
1699*7c478bd9Sstevel@tonic-gate 			break;
1700*7c478bd9Sstevel@tonic-gate 
1701*7c478bd9Sstevel@tonic-gate 		case TG_DEAD:
1702*7c478bd9Sstevel@tonic-gate 			if (tg->tg_latime + MIN_RECOVERY_TIME < now) {
1703*7c478bd9Sstevel@tonic-gate 				dead_recovered = tg;
1704*7c478bd9Sstevel@tonic-gate 				/*
1705*7c478bd9Sstevel@tonic-gate 				 * Promote the dead_recoverd to slow
1706*7c478bd9Sstevel@tonic-gate 				 */
1707*7c478bd9Sstevel@tonic-gate 				tg->tg_status = TG_SLOW;
1708*7c478bd9Sstevel@tonic-gate 				tg->tg_latime = now;
1709*7c478bd9Sstevel@tonic-gate 			} else {
1710*7c478bd9Sstevel@tonic-gate 				dead = tg;
1711*7c478bd9Sstevel@tonic-gate 			}
1712*7c478bd9Sstevel@tonic-gate 			break;
1713*7c478bd9Sstevel@tonic-gate 
1714*7c478bd9Sstevel@tonic-gate 		default:
1715*7c478bd9Sstevel@tonic-gate 			break;
1716*7c478bd9Sstevel@tonic-gate 		}
1717*7c478bd9Sstevel@tonic-gate 	}
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate 	if (slow_recovered != NULL)
1720*7c478bd9Sstevel@tonic-gate 		return (slow_recovered);
1721*7c478bd9Sstevel@tonic-gate 	else if (slow != NULL)
1722*7c478bd9Sstevel@tonic-gate 		return (slow);
1723*7c478bd9Sstevel@tonic-gate 	else if (dead_recovered != NULL)
1724*7c478bd9Sstevel@tonic-gate 		return (dead_recovered);
1725*7c478bd9Sstevel@tonic-gate 	else
1726*7c478bd9Sstevel@tonic-gate 		return (dead);
1727*7c478bd9Sstevel@tonic-gate }
1728*7c478bd9Sstevel@tonic-gate 
1729*7c478bd9Sstevel@tonic-gate /*
1730*7c478bd9Sstevel@tonic-gate  * Some target was deleted. If we don't have even MIN_PROBE_TARGETS
1731*7c478bd9Sstevel@tonic-gate  * that are active, pick the next best below.
1732*7c478bd9Sstevel@tonic-gate  */
1733*7c478bd9Sstevel@tonic-gate static void
1734*7c478bd9Sstevel@tonic-gate target_activate_all(struct phyint_instance *pii)
1735*7c478bd9Sstevel@tonic-gate {
1736*7c478bd9Sstevel@tonic-gate 	struct target *tg;
1737*7c478bd9Sstevel@tonic-gate 
1738*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_ntargets == 0);
1739*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_target_next == NULL);
1740*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_rtt_target_next == NULL);
1741*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets_are_routers);
1742*7c478bd9Sstevel@tonic-gate 
1743*7c478bd9Sstevel@tonic-gate 	while (pii->pii_ntargets < MIN_PROBE_TARGETS) {
1744*7c478bd9Sstevel@tonic-gate 		tg = target_select_best(pii);
1745*7c478bd9Sstevel@tonic-gate 		if (tg == NULL) {
1746*7c478bd9Sstevel@tonic-gate 			/* We are out of targets */
1747*7c478bd9Sstevel@tonic-gate 			return;
1748*7c478bd9Sstevel@tonic-gate 		}
1749*7c478bd9Sstevel@tonic-gate 
1750*7c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
1751*7c478bd9Sstevel@tonic-gate 		assert(tg->tg_status != TG_ACTIVE);
1752*7c478bd9Sstevel@tonic-gate 		tg->tg_status = TG_ACTIVE;
1753*7c478bd9Sstevel@tonic-gate 		pii->pii_ntargets++;
1754*7c478bd9Sstevel@tonic-gate 		if (pii->pii_target_next == NULL) {
1755*7c478bd9Sstevel@tonic-gate 			pii->pii_target_next = tg;
1756*7c478bd9Sstevel@tonic-gate 			pii->pii_rtt_target_next = tg;
1757*7c478bd9Sstevel@tonic-gate 		}
1758*7c478bd9Sstevel@tonic-gate 	}
1759*7c478bd9Sstevel@tonic-gate }
1760*7c478bd9Sstevel@tonic-gate 
1761*7c478bd9Sstevel@tonic-gate static struct target *
1762*7c478bd9Sstevel@tonic-gate target_first(struct phyint_instance *pii)
1763*7c478bd9Sstevel@tonic-gate {
1764*7c478bd9Sstevel@tonic-gate 	struct target *tg;
1765*7c478bd9Sstevel@tonic-gate 
1766*7c478bd9Sstevel@tonic-gate 	for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) {
1767*7c478bd9Sstevel@tonic-gate 		assert(TG_STATUS_VALID(tg->tg_status));
1768*7c478bd9Sstevel@tonic-gate 		if (tg->tg_status == TG_ACTIVE)
1769*7c478bd9Sstevel@tonic-gate 			break;
1770*7c478bd9Sstevel@tonic-gate 	}
1771*7c478bd9Sstevel@tonic-gate 
1772*7c478bd9Sstevel@tonic-gate 	return (tg);
1773*7c478bd9Sstevel@tonic-gate }
1774*7c478bd9Sstevel@tonic-gate 
1775*7c478bd9Sstevel@tonic-gate /*
1776*7c478bd9Sstevel@tonic-gate  * Create a default target entry.
1777*7c478bd9Sstevel@tonic-gate  */
1778*7c478bd9Sstevel@tonic-gate void
1779*7c478bd9Sstevel@tonic-gate target_create(struct phyint_instance *pii, struct in6_addr addr,
1780*7c478bd9Sstevel@tonic-gate     boolean_t is_router)
1781*7c478bd9Sstevel@tonic-gate {
1782*7c478bd9Sstevel@tonic-gate 	struct target *tg;
1783*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
1784*7c478bd9Sstevel@tonic-gate 	struct logint *li;
1785*7c478bd9Sstevel@tonic-gate 
1786*7c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET) {
1787*7c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
1788*7c478bd9Sstevel@tonic-gate 
1789*7c478bd9Sstevel@tonic-gate 		logdebug("target_create(%s %s, %s)\n",
1790*7c478bd9Sstevel@tonic-gate 		    AF_STR(pii->pii_af), pii->pii_name,
1791*7c478bd9Sstevel@tonic-gate 		    pr_addr(pii->pii_af, addr, abuf, sizeof (abuf)));
1792*7c478bd9Sstevel@tonic-gate 	}
1793*7c478bd9Sstevel@tonic-gate 
1794*7c478bd9Sstevel@tonic-gate 	/*
1795*7c478bd9Sstevel@tonic-gate 	 * If the test address is not yet initialized, do not add
1796*7c478bd9Sstevel@tonic-gate 	 * any target, since we cannot determine whether the target
1797*7c478bd9Sstevel@tonic-gate 	 * belongs to the same subnet as the test address.
1798*7c478bd9Sstevel@tonic-gate 	 */
1799*7c478bd9Sstevel@tonic-gate 	li = pii->pii_probe_logint;
1800*7c478bd9Sstevel@tonic-gate 	if (li == NULL)
1801*7c478bd9Sstevel@tonic-gate 		return;
1802*7c478bd9Sstevel@tonic-gate 
1803*7c478bd9Sstevel@tonic-gate 	/*
1804*7c478bd9Sstevel@tonic-gate 	 * If there are multiple subnets associated with an interface, then
1805*7c478bd9Sstevel@tonic-gate 	 * add the target to this phyint instance, only if it belongs to the
1806*7c478bd9Sstevel@tonic-gate 	 * same subnet as the test address. The reason is that interface
1807*7c478bd9Sstevel@tonic-gate 	 * routes derived from non-test-addresses i.e. non-IFF_NOFAILOVER
1808*7c478bd9Sstevel@tonic-gate 	 * addresses, will disappear after failover, and the targets will not
1809*7c478bd9Sstevel@tonic-gate 	 * be reachable from this interface.
1810*7c478bd9Sstevel@tonic-gate 	 */
1811*7c478bd9Sstevel@tonic-gate 	if (!prefix_equal(li->li_subnet, addr, li->li_subnet_len))
1812*7c478bd9Sstevel@tonic-gate 		return;
1813*7c478bd9Sstevel@tonic-gate 
1814*7c478bd9Sstevel@tonic-gate 	if (pii->pii_targets != NULL) {
1815*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_ntargets <= MAX_PROBE_TARGETS);
1816*7c478bd9Sstevel@tonic-gate 		if (is_router) {
1817*7c478bd9Sstevel@tonic-gate 			if (!pii->pii_targets_are_routers) {
1818*7c478bd9Sstevel@tonic-gate 				/*
1819*7c478bd9Sstevel@tonic-gate 				 * Prefer router over hosts. Using hosts is a
1820*7c478bd9Sstevel@tonic-gate 				 * fallback mechanism, hence delete all host
1821*7c478bd9Sstevel@tonic-gate 				 * targets.
1822*7c478bd9Sstevel@tonic-gate 				 */
1823*7c478bd9Sstevel@tonic-gate 				while (pii->pii_targets != NULL)
1824*7c478bd9Sstevel@tonic-gate 					target_delete(pii->pii_targets);
1825*7c478bd9Sstevel@tonic-gate 			}
1826*7c478bd9Sstevel@tonic-gate 		} else {
1827*7c478bd9Sstevel@tonic-gate 			/*
1828*7c478bd9Sstevel@tonic-gate 			 * Routers take precedence over hosts. If this
1829*7c478bd9Sstevel@tonic-gate 			 * is a router list and we are trying to add a
1830*7c478bd9Sstevel@tonic-gate 			 * host, just return. If this is a host list
1831*7c478bd9Sstevel@tonic-gate 			 * and if we have sufficient targets, just return
1832*7c478bd9Sstevel@tonic-gate 			 */
1833*7c478bd9Sstevel@tonic-gate 			if (pii->pii_targets_are_routers ||
1834*7c478bd9Sstevel@tonic-gate 			    pii->pii_ntargets == MAX_PROBE_TARGETS)
1835*7c478bd9Sstevel@tonic-gate 				return;
1836*7c478bd9Sstevel@tonic-gate 		}
1837*7c478bd9Sstevel@tonic-gate 	}
1838*7c478bd9Sstevel@tonic-gate 
1839*7c478bd9Sstevel@tonic-gate 	tg = calloc(1, sizeof (struct target));
1840*7c478bd9Sstevel@tonic-gate 	if (tg == NULL) {
1841*7c478bd9Sstevel@tonic-gate 		logperror("target_create: calloc");
1842*7c478bd9Sstevel@tonic-gate 		return;
1843*7c478bd9Sstevel@tonic-gate 	}
1844*7c478bd9Sstevel@tonic-gate 
1845*7c478bd9Sstevel@tonic-gate 	tg->tg_phyint_inst = pii;
1846*7c478bd9Sstevel@tonic-gate 	tg->tg_address = addr;
1847*7c478bd9Sstevel@tonic-gate 	tg->tg_in_use = 1;
1848*7c478bd9Sstevel@tonic-gate 	tg->tg_rtt_sa = -1;
1849*7c478bd9Sstevel@tonic-gate 	tg->tg_num_deferred = 0;
1850*7c478bd9Sstevel@tonic-gate 
1851*7c478bd9Sstevel@tonic-gate 	/*
1852*7c478bd9Sstevel@tonic-gate 	 * If this is the first target, set 'pii_targets_are_routers'
1853*7c478bd9Sstevel@tonic-gate 	 * The list of targets is either a list of hosts or list or
1854*7c478bd9Sstevel@tonic-gate 	 * routers, but not a mix.
1855*7c478bd9Sstevel@tonic-gate 	 */
1856*7c478bd9Sstevel@tonic-gate 	if (pii->pii_targets == NULL) {
1857*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_ntargets == 0);
1858*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next == NULL);
1859*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next == NULL);
1860*7c478bd9Sstevel@tonic-gate 		pii->pii_targets_are_routers = is_router ? 1 : 0;
1861*7c478bd9Sstevel@tonic-gate 	}
1862*7c478bd9Sstevel@tonic-gate 
1863*7c478bd9Sstevel@tonic-gate 	if (pii->pii_ntargets == MAX_PROBE_TARGETS) {
1864*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_targets_are_routers);
1865*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next != NULL);
1866*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next != NULL);
1867*7c478bd9Sstevel@tonic-gate 		tg->tg_status = TG_UNUSED;
1868*7c478bd9Sstevel@tonic-gate 	} else {
1869*7c478bd9Sstevel@tonic-gate 		if (pii->pii_ntargets == 0) {
1870*7c478bd9Sstevel@tonic-gate 			assert(pii->pii_target_next == NULL);
1871*7c478bd9Sstevel@tonic-gate 			pii->pii_target_next = tg;
1872*7c478bd9Sstevel@tonic-gate 			pii->pii_rtt_target_next = tg;
1873*7c478bd9Sstevel@tonic-gate 		}
1874*7c478bd9Sstevel@tonic-gate 		pii->pii_ntargets++;
1875*7c478bd9Sstevel@tonic-gate 		tg->tg_status = TG_ACTIVE;
1876*7c478bd9Sstevel@tonic-gate 	}
1877*7c478bd9Sstevel@tonic-gate 
1878*7c478bd9Sstevel@tonic-gate 	target_insert(pii, tg);
1879*7c478bd9Sstevel@tonic-gate 
1880*7c478bd9Sstevel@tonic-gate 	/*
1881*7c478bd9Sstevel@tonic-gate 	 * Change to running state, if this phyint instance is capable of
1882*7c478bd9Sstevel@tonic-gate 	 * sending and receiving probes. i.e if we know of at least 1 target,
1883*7c478bd9Sstevel@tonic-gate 	 * and this phyint instance socket is bound to the IFF_NOFAILOVER
1884*7c478bd9Sstevel@tonic-gate 	 * address. More details in phyint state diagram in probe.c.
1885*7c478bd9Sstevel@tonic-gate 	 */
1886*7c478bd9Sstevel@tonic-gate 	pi = pii->pii_phyint;
1887*7c478bd9Sstevel@tonic-gate 	if (pi->pi_state == PI_NOTARGETS && PROBE_CAPABLE(pii)) {
1888*7c478bd9Sstevel@tonic-gate 		if (pi->pi_flags & IFF_FAILED)
1889*7c478bd9Sstevel@tonic-gate 			phyint_chstate(pi, PI_FAILED);
1890*7c478bd9Sstevel@tonic-gate 		else
1891*7c478bd9Sstevel@tonic-gate 			phyint_chstate(pi, PI_RUNNING);
1892*7c478bd9Sstevel@tonic-gate 	}
1893*7c478bd9Sstevel@tonic-gate }
1894*7c478bd9Sstevel@tonic-gate 
1895*7c478bd9Sstevel@tonic-gate /*
1896*7c478bd9Sstevel@tonic-gate  * Add the target address named by `addr' to phyint instance `pii' if it does
1897*7c478bd9Sstevel@tonic-gate  * not already exist.  If the target is a router, `is_router' should be set to
1898*7c478bd9Sstevel@tonic-gate  * B_TRUE.
1899*7c478bd9Sstevel@tonic-gate  */
1900*7c478bd9Sstevel@tonic-gate void
1901*7c478bd9Sstevel@tonic-gate target_add(struct phyint_instance *pii, struct in6_addr addr,
1902*7c478bd9Sstevel@tonic-gate     boolean_t is_router)
1903*7c478bd9Sstevel@tonic-gate {
1904*7c478bd9Sstevel@tonic-gate 	struct target *tg;
1905*7c478bd9Sstevel@tonic-gate 
1906*7c478bd9Sstevel@tonic-gate 	if (pii == NULL)
1907*7c478bd9Sstevel@tonic-gate 		return;
1908*7c478bd9Sstevel@tonic-gate 
1909*7c478bd9Sstevel@tonic-gate 	tg = target_lookup(pii, addr);
1910*7c478bd9Sstevel@tonic-gate 
1911*7c478bd9Sstevel@tonic-gate 	/*
1912*7c478bd9Sstevel@tonic-gate 	 * If the target does not exist, create it; target_create() will set
1913*7c478bd9Sstevel@tonic-gate 	 * tg_in_use to true.  If it exists already, and it is a router
1914*7c478bd9Sstevel@tonic-gate 	 * target, set tg_in_use to to true, so that init_router_targets()
1915*7c478bd9Sstevel@tonic-gate 	 * won't delete it
1916*7c478bd9Sstevel@tonic-gate 	 */
1917*7c478bd9Sstevel@tonic-gate 	if (tg == NULL)
1918*7c478bd9Sstevel@tonic-gate 		target_create(pii, addr, is_router);
1919*7c478bd9Sstevel@tonic-gate 	else if (is_router)
1920*7c478bd9Sstevel@tonic-gate 		tg->tg_in_use = 1;
1921*7c478bd9Sstevel@tonic-gate }
1922*7c478bd9Sstevel@tonic-gate 
1923*7c478bd9Sstevel@tonic-gate /*
1924*7c478bd9Sstevel@tonic-gate  * Insert target at head of linked list of targets for the associated
1925*7c478bd9Sstevel@tonic-gate  * phyint instance
1926*7c478bd9Sstevel@tonic-gate  */
1927*7c478bd9Sstevel@tonic-gate static void
1928*7c478bd9Sstevel@tonic-gate target_insert(struct phyint_instance *pii, struct target *tg)
1929*7c478bd9Sstevel@tonic-gate {
1930*7c478bd9Sstevel@tonic-gate 	tg->tg_next = pii->pii_targets;
1931*7c478bd9Sstevel@tonic-gate 	tg->tg_prev = NULL;
1932*7c478bd9Sstevel@tonic-gate 	if (tg->tg_next != NULL)
1933*7c478bd9Sstevel@tonic-gate 		tg->tg_next->tg_prev = tg;
1934*7c478bd9Sstevel@tonic-gate 	pii->pii_targets = tg;
1935*7c478bd9Sstevel@tonic-gate }
1936*7c478bd9Sstevel@tonic-gate 
1937*7c478bd9Sstevel@tonic-gate /*
1938*7c478bd9Sstevel@tonic-gate  * Delete a target (unlink and free).
1939*7c478bd9Sstevel@tonic-gate  */
1940*7c478bd9Sstevel@tonic-gate void
1941*7c478bd9Sstevel@tonic-gate target_delete(struct target *tg)
1942*7c478bd9Sstevel@tonic-gate {
1943*7c478bd9Sstevel@tonic-gate 	int af;
1944*7c478bd9Sstevel@tonic-gate 	struct phyint_instance	*pii;
1945*7c478bd9Sstevel@tonic-gate 	struct phyint_instance	*pii_other;
1946*7c478bd9Sstevel@tonic-gate 
1947*7c478bd9Sstevel@tonic-gate 	pii = tg->tg_phyint_inst;
1948*7c478bd9Sstevel@tonic-gate 	af = pii->pii_af;
1949*7c478bd9Sstevel@tonic-gate 
1950*7c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET) {
1951*7c478bd9Sstevel@tonic-gate 		char abuf[INET6_ADDRSTRLEN];
1952*7c478bd9Sstevel@tonic-gate 
1953*7c478bd9Sstevel@tonic-gate 		logdebug("target_delete(%s %s, %s)\n",
1954*7c478bd9Sstevel@tonic-gate 		    AF_STR(af), pii->pii_name,
1955*7c478bd9Sstevel@tonic-gate 		    pr_addr(af, tg->tg_address, abuf, sizeof (abuf)));
1956*7c478bd9Sstevel@tonic-gate 	}
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate 	/*
1959*7c478bd9Sstevel@tonic-gate 	 * Target must be in the list of targets for this phyint
1960*7c478bd9Sstevel@tonic-gate 	 * instance.
1961*7c478bd9Sstevel@tonic-gate 	 */
1962*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets == tg || tg->tg_prev != NULL);
1963*7c478bd9Sstevel@tonic-gate 
1964*7c478bd9Sstevel@tonic-gate 	/*
1965*7c478bd9Sstevel@tonic-gate 	 * Reset all references to 'tg' in the probe information
1966*7c478bd9Sstevel@tonic-gate 	 * for this phyint.
1967*7c478bd9Sstevel@tonic-gate 	 */
1968*7c478bd9Sstevel@tonic-gate 	reset_pii_probes(pii, tg);
1969*7c478bd9Sstevel@tonic-gate 
1970*7c478bd9Sstevel@tonic-gate 	/*
1971*7c478bd9Sstevel@tonic-gate 	 * Remove this target from the list of targets of this
1972*7c478bd9Sstevel@tonic-gate 	 * phyint instance.
1973*7c478bd9Sstevel@tonic-gate 	 */
1974*7c478bd9Sstevel@tonic-gate 	if (tg->tg_prev == NULL) {
1975*7c478bd9Sstevel@tonic-gate 		pii->pii_targets = tg->tg_next;
1976*7c478bd9Sstevel@tonic-gate 	} else {
1977*7c478bd9Sstevel@tonic-gate 		tg->tg_prev->tg_next = tg->tg_next;
1978*7c478bd9Sstevel@tonic-gate 	}
1979*7c478bd9Sstevel@tonic-gate 
1980*7c478bd9Sstevel@tonic-gate 	if (tg->tg_next != NULL)
1981*7c478bd9Sstevel@tonic-gate 		tg->tg_next->tg_prev = tg->tg_prev;
1982*7c478bd9Sstevel@tonic-gate 
1983*7c478bd9Sstevel@tonic-gate 	tg->tg_next = NULL;
1984*7c478bd9Sstevel@tonic-gate 	tg->tg_prev = NULL;
1985*7c478bd9Sstevel@tonic-gate 
1986*7c478bd9Sstevel@tonic-gate 	if (tg->tg_status == TG_ACTIVE)
1987*7c478bd9Sstevel@tonic-gate 		pii->pii_ntargets--;
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate 	/*
1990*7c478bd9Sstevel@tonic-gate 	 * Adjust the next target to probe, if it points to
1991*7c478bd9Sstevel@tonic-gate 	 * to the currently deleted target.
1992*7c478bd9Sstevel@tonic-gate 	 */
1993*7c478bd9Sstevel@tonic-gate 	if (pii->pii_target_next == tg)
1994*7c478bd9Sstevel@tonic-gate 		pii->pii_target_next = target_first(pii);
1995*7c478bd9Sstevel@tonic-gate 
1996*7c478bd9Sstevel@tonic-gate 	if (pii->pii_rtt_target_next == tg)
1997*7c478bd9Sstevel@tonic-gate 		pii->pii_rtt_target_next = target_first(pii);
1998*7c478bd9Sstevel@tonic-gate 
1999*7c478bd9Sstevel@tonic-gate 	free(tg);
2000*7c478bd9Sstevel@tonic-gate 
2001*7c478bd9Sstevel@tonic-gate 	/*
2002*7c478bd9Sstevel@tonic-gate 	 * The number of active targets pii_ntargets == 0 iff
2003*7c478bd9Sstevel@tonic-gate 	 * the next active target pii->pii_target_next == NULL
2004*7c478bd9Sstevel@tonic-gate 	 */
2005*7c478bd9Sstevel@tonic-gate 	if (pii->pii_ntargets != 0) {
2006*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next != NULL);
2007*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next != NULL);
2008*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_target_next->tg_status == TG_ACTIVE);
2009*7c478bd9Sstevel@tonic-gate 		assert(pii->pii_rtt_target_next->tg_status == TG_ACTIVE);
2010*7c478bd9Sstevel@tonic-gate 		return;
2011*7c478bd9Sstevel@tonic-gate 	}
2012*7c478bd9Sstevel@tonic-gate 
2013*7c478bd9Sstevel@tonic-gate 	/* At this point, we don't have any active targets. */
2014*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_target_next == NULL);
2015*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_rtt_target_next == NULL);
2016*7c478bd9Sstevel@tonic-gate 
2017*7c478bd9Sstevel@tonic-gate 	if (pii->pii_targets_are_routers) {
2018*7c478bd9Sstevel@tonic-gate 		/*
2019*7c478bd9Sstevel@tonic-gate 		 * Activate any TG_SLOW or TG_DEAD router targets,
2020*7c478bd9Sstevel@tonic-gate 		 * since we don't have any other targets
2021*7c478bd9Sstevel@tonic-gate 		 */
2022*7c478bd9Sstevel@tonic-gate 		target_activate_all(pii);
2023*7c478bd9Sstevel@tonic-gate 
2024*7c478bd9Sstevel@tonic-gate 		if (pii->pii_ntargets != 0) {
2025*7c478bd9Sstevel@tonic-gate 			assert(pii->pii_target_next != NULL);
2026*7c478bd9Sstevel@tonic-gate 			assert(pii->pii_rtt_target_next != NULL);
2027*7c478bd9Sstevel@tonic-gate 			assert(pii->pii_target_next->tg_status == TG_ACTIVE);
2028*7c478bd9Sstevel@tonic-gate 			assert(pii->pii_rtt_target_next->tg_status ==
2029*7c478bd9Sstevel@tonic-gate 			    TG_ACTIVE);
2030*7c478bd9Sstevel@tonic-gate 			return;
2031*7c478bd9Sstevel@tonic-gate 		}
2032*7c478bd9Sstevel@tonic-gate 	}
2033*7c478bd9Sstevel@tonic-gate 
2034*7c478bd9Sstevel@tonic-gate 	/*
2035*7c478bd9Sstevel@tonic-gate 	 * If we still don't have any active targets, the list must
2036*7c478bd9Sstevel@tonic-gate 	 * must be really empty. There aren't even TG_SLOW or TG_DEAD
2037*7c478bd9Sstevel@tonic-gate 	 * targets. Zero out the probe stats since it will not be
2038*7c478bd9Sstevel@tonic-gate 	 * relevant any longer.
2039*7c478bd9Sstevel@tonic-gate 	 */
2040*7c478bd9Sstevel@tonic-gate 	assert(pii->pii_targets == NULL);
2041*7c478bd9Sstevel@tonic-gate 	clear_pii_probe_stats(pii);
2042*7c478bd9Sstevel@tonic-gate 	pii_other = phyint_inst_other(pii);
2043*7c478bd9Sstevel@tonic-gate 
2044*7c478bd9Sstevel@tonic-gate 	/*
2045*7c478bd9Sstevel@tonic-gate 	 * If there are no targets on both instances,
2046*7c478bd9Sstevel@tonic-gate 	 * go back to PI_NOTARGETS state, since we cannot
2047*7c478bd9Sstevel@tonic-gate 	 * probe this phyint any more. For more details,
2048*7c478bd9Sstevel@tonic-gate 	 * please see phyint state diagram in mpd_probe.c.
2049*7c478bd9Sstevel@tonic-gate 	 */
2050*7c478bd9Sstevel@tonic-gate 	if (!PROBE_CAPABLE(pii_other))
2051*7c478bd9Sstevel@tonic-gate 		phyint_chstate(pii->pii_phyint, PI_NOTARGETS);
2052*7c478bd9Sstevel@tonic-gate }
2053*7c478bd9Sstevel@tonic-gate 
2054*7c478bd9Sstevel@tonic-gate /*
2055*7c478bd9Sstevel@tonic-gate  * Flush the target list of every phyint in the group, if the list
2056*7c478bd9Sstevel@tonic-gate  * is a host target list. This is called if group failure is suspected.
2057*7c478bd9Sstevel@tonic-gate  * If all targets have failed, multicast will subsequently discover new
2058*7c478bd9Sstevel@tonic-gate  * targets. Else it is a group failure.
2059*7c478bd9Sstevel@tonic-gate  * Note: This function is a no-op if the list is a router target list.
2060*7c478bd9Sstevel@tonic-gate  */
2061*7c478bd9Sstevel@tonic-gate static void
2062*7c478bd9Sstevel@tonic-gate target_flush_hosts(struct phyint_group *pg)
2063*7c478bd9Sstevel@tonic-gate {
2064*7c478bd9Sstevel@tonic-gate 	struct phyint *pi;
2065*7c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
2066*7c478bd9Sstevel@tonic-gate 
2067*7c478bd9Sstevel@tonic-gate 	if (debug & D_TARGET)
2068*7c478bd9Sstevel@tonic-gate 		logdebug("target_flush_hosts(%s)\n", pg->pg_name);
2069*7c478bd9Sstevel@tonic-gate 
2070*7c478bd9Sstevel@tonic-gate 	for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext) {
2071*7c478bd9Sstevel@tonic-gate 		pii = pi->pi_v4;
2072*7c478bd9Sstevel@tonic-gate 		if (pii != NULL && !pii->pii_targets_are_routers) {
2073*7c478bd9Sstevel@tonic-gate 			/*
2074*7c478bd9Sstevel@tonic-gate 			 * Delete all the targets. When the list becomes
2075*7c478bd9Sstevel@tonic-gate 			 * empty, target_delete() will set pii->pii_targets
2076*7c478bd9Sstevel@tonic-gate 			 * to NULL.
2077*7c478bd9Sstevel@tonic-gate 			 */
2078*7c478bd9Sstevel@tonic-gate 			while (pii->pii_targets != NULL)
2079*7c478bd9Sstevel@tonic-gate 				target_delete(pii->pii_targets);
2080*7c478bd9Sstevel@tonic-gate 		}
2081*7c478bd9Sstevel@tonic-gate 		pii = pi->pi_v6;
2082*7c478bd9Sstevel@tonic-gate 		if (pii != NULL && !pii->pii_targets_are_routers) {
2083*7c478bd9Sstevel@tonic-gate 			/*
2084*7c478bd9Sstevel@tonic-gate 			 * Delete all the targets. When the list becomes
2085*7c478bd9Sstevel@tonic-gate 			 * empty, target_delete() will set pii->pii_targets
2086*7c478bd9Sstevel@tonic-gate 			 * to NULL.
2087*7c478bd9Sstevel@tonic-gate 			 */
2088*7c478bd9Sstevel@tonic-gate 			while (pii->pii_targets != NULL)
2089*7c478bd9Sstevel@tonic-gate 				target_delete(pii->pii_targets);
2090*7c478bd9Sstevel@tonic-gate 		}
2091*7c478bd9Sstevel@tonic-gate 	}
2092*7c478bd9Sstevel@tonic-gate }
2093*7c478bd9Sstevel@tonic-gate 
2094*7c478bd9Sstevel@tonic-gate /*
2095*7c478bd9Sstevel@tonic-gate  * Reset all references to 'target' in the probe info, as this target is
2096*7c478bd9Sstevel@tonic-gate  * being deleted. The pr_target field is guaranteed to be non-null if
2097*7c478bd9Sstevel@tonic-gate  * pr_status is PR_UNACKED. So we change the pr_status to PR_LOST, so that
2098*7c478bd9Sstevel@tonic-gate  * pr_target will not be accessed unconditionally.
2099*7c478bd9Sstevel@tonic-gate  */
2100*7c478bd9Sstevel@tonic-gate static void
2101*7c478bd9Sstevel@tonic-gate reset_pii_probes(struct phyint_instance *pii, struct target *tg)
2102*7c478bd9Sstevel@tonic-gate {
2103*7c478bd9Sstevel@tonic-gate 	int i;
2104*7c478bd9Sstevel@tonic-gate 
2105*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < PROBE_STATS_COUNT; i++) {
2106*7c478bd9Sstevel@tonic-gate 		if (pii->pii_probes[i].pr_target == tg) {
2107*7c478bd9Sstevel@tonic-gate 			pii->pii_probes[i].pr_target = NULL;
2108*7c478bd9Sstevel@tonic-gate 			if (pii->pii_probes[i].pr_status == PR_UNACKED)
2109*7c478bd9Sstevel@tonic-gate 				pii->pii_probes[i].pr_status = PR_LOST;
2110*7c478bd9Sstevel@tonic-gate 		}
2111*7c478bd9Sstevel@tonic-gate 	}
2112*7c478bd9Sstevel@tonic-gate 
2113*7c478bd9Sstevel@tonic-gate }
2114*7c478bd9Sstevel@tonic-gate 
2115*7c478bd9Sstevel@tonic-gate /*
2116*7c478bd9Sstevel@tonic-gate  * Clear the probe statistics array.
2117*7c478bd9Sstevel@tonic-gate  */
2118*7c478bd9Sstevel@tonic-gate void
2119*7c478bd9Sstevel@tonic-gate clear_pii_probe_stats(struct phyint_instance *pii)
2120*7c478bd9Sstevel@tonic-gate {
2121*7c478bd9Sstevel@tonic-gate 	bzero(pii->pii_probes, sizeof (struct probe_stats) * PROBE_STATS_COUNT);
2122*7c478bd9Sstevel@tonic-gate 	/* Reset the next probe index in the probe stats array */
2123*7c478bd9Sstevel@tonic-gate 	pii->pii_probe_next = 0;
2124*7c478bd9Sstevel@tonic-gate }
2125*7c478bd9Sstevel@tonic-gate 
2126*7c478bd9Sstevel@tonic-gate static void
2127*7c478bd9Sstevel@tonic-gate target_print(struct target *tg)
2128*7c478bd9Sstevel@tonic-gate {
2129*7c478bd9Sstevel@tonic-gate 	char	abuf[INET6_ADDRSTRLEN];
2130*7c478bd9Sstevel@tonic-gate 	char	buf[128];
2131*7c478bd9Sstevel@tonic-gate 	char	buf2[128];
2132*7c478bd9Sstevel@tonic-gate 	int	af;
2133*7c478bd9Sstevel@tonic-gate 	int	i;
2134*7c478bd9Sstevel@tonic-gate 
2135*7c478bd9Sstevel@tonic-gate 	af = tg->tg_phyint_inst->pii_af;
2136*7c478bd9Sstevel@tonic-gate 
2137*7c478bd9Sstevel@tonic-gate 	logdebug("Target on %s %s addr %s\n"
2138*7c478bd9Sstevel@tonic-gate 	    "status %d rtt_sa %d rtt_sd %d crtt %d tg_in_use %d\n",
2139*7c478bd9Sstevel@tonic-gate 	    AF_STR(af), tg->tg_phyint_inst->pii_name,
2140*7c478bd9Sstevel@tonic-gate 	    pr_addr(af, tg->tg_address, abuf, sizeof (abuf)),
2141*7c478bd9Sstevel@tonic-gate 	    tg->tg_status, tg->tg_rtt_sa, tg->tg_rtt_sd,
2142*7c478bd9Sstevel@tonic-gate 	    tg->tg_crtt, tg->tg_in_use);
2143*7c478bd9Sstevel@tonic-gate 
2144*7c478bd9Sstevel@tonic-gate 	buf[0] = '\0';
2145*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < tg->tg_num_deferred; i++) {
2146*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf2, sizeof (buf2), " %dms",
2147*7c478bd9Sstevel@tonic-gate 		    tg->tg_deferred[i]);
2148*7c478bd9Sstevel@tonic-gate 		(void) strlcat(buf, buf2, sizeof (buf));
2149*7c478bd9Sstevel@tonic-gate 	}
2150*7c478bd9Sstevel@tonic-gate 	logdebug("deferred rtts:%s\n", buf);
2151*7c478bd9Sstevel@tonic-gate }
2152*7c478bd9Sstevel@tonic-gate 
2153*7c478bd9Sstevel@tonic-gate void
2154*7c478bd9Sstevel@tonic-gate phyint_inst_print_all(void)
2155*7c478bd9Sstevel@tonic-gate {
2156*7c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
2157*7c478bd9Sstevel@tonic-gate 
2158*7c478bd9Sstevel@tonic-gate 	for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) {
2159*7c478bd9Sstevel@tonic-gate 		phyint_inst_print(pii);
2160*7c478bd9Sstevel@tonic-gate 	}
2161*7c478bd9Sstevel@tonic-gate }
2162*7c478bd9Sstevel@tonic-gate 
2163*7c478bd9Sstevel@tonic-gate /*
2164*7c478bd9Sstevel@tonic-gate  * Convert length for a mask to the mask.
2165*7c478bd9Sstevel@tonic-gate  */
2166*7c478bd9Sstevel@tonic-gate static void
2167*7c478bd9Sstevel@tonic-gate ip_index_to_mask_v6(uint_t masklen, struct in6_addr *bitmask)
2168*7c478bd9Sstevel@tonic-gate {
2169*7c478bd9Sstevel@tonic-gate 	int	j;
2170*7c478bd9Sstevel@tonic-gate 
2171*7c478bd9Sstevel@tonic-gate 	assert(masklen <= IPV6_ABITS);
2172*7c478bd9Sstevel@tonic-gate 	bzero((char *)bitmask, sizeof (*bitmask));
2173*7c478bd9Sstevel@tonic-gate 
2174*7c478bd9Sstevel@tonic-gate 	/* Make the 'masklen' leftmost bits one */
2175*7c478bd9Sstevel@tonic-gate 	for (j = 0; masklen > 8; masklen -= 8, j++)
2176*7c478bd9Sstevel@tonic-gate 		bitmask->s6_addr[j] = 0xff;
2177*7c478bd9Sstevel@tonic-gate 
2178*7c478bd9Sstevel@tonic-gate 	bitmask->s6_addr[j] = 0xff << (8 - masklen);
2179*7c478bd9Sstevel@tonic-gate 
2180*7c478bd9Sstevel@tonic-gate }
2181*7c478bd9Sstevel@tonic-gate 
2182*7c478bd9Sstevel@tonic-gate /*
2183*7c478bd9Sstevel@tonic-gate  * Compare two prefixes that have the same prefix length.
2184*7c478bd9Sstevel@tonic-gate  * Fails if the prefix length is unreasonable.
2185*7c478bd9Sstevel@tonic-gate  */
2186*7c478bd9Sstevel@tonic-gate static boolean_t
2187*7c478bd9Sstevel@tonic-gate prefix_equal(struct in6_addr p1, struct in6_addr p2, int prefix_len)
2188*7c478bd9Sstevel@tonic-gate {
2189*7c478bd9Sstevel@tonic-gate 	uchar_t mask;
2190*7c478bd9Sstevel@tonic-gate 	int j;
2191*7c478bd9Sstevel@tonic-gate 
2192*7c478bd9Sstevel@tonic-gate 	if (prefix_len < 0 || prefix_len > IPV6_ABITS)
2193*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
2194*7c478bd9Sstevel@tonic-gate 
2195*7c478bd9Sstevel@tonic-gate 	for (j = 0; prefix_len > 8; prefix_len -= 8, j++)
2196*7c478bd9Sstevel@tonic-gate 		if (p1.s6_addr[j] != p2.s6_addr[j])
2197*7c478bd9Sstevel@tonic-gate 			return (_B_FALSE);
2198*7c478bd9Sstevel@tonic-gate 
2199*7c478bd9Sstevel@tonic-gate 	/* Make the N leftmost bits one */
2200*7c478bd9Sstevel@tonic-gate 	mask = 0xff << (8 - prefix_len);
2201*7c478bd9Sstevel@tonic-gate 	if ((p1.s6_addr[j] & mask) != (p2.s6_addr[j] & mask))
2202*7c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
2203*7c478bd9Sstevel@tonic-gate 
2204*7c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
2205*7c478bd9Sstevel@tonic-gate }
2206*7c478bd9Sstevel@tonic-gate 
2207*7c478bd9Sstevel@tonic-gate /*
2208*7c478bd9Sstevel@tonic-gate  * Get the number of UP logints (excluding IFF_NOFAILOVERs), on both
2209*7c478bd9Sstevel@tonic-gate  * IPv4 and IPv6 put together. The phyint with the least such number
2210*7c478bd9Sstevel@tonic-gate  * will be used as the failover destination, if no standby interface is
2211*7c478bd9Sstevel@tonic-gate  * available
2212*7c478bd9Sstevel@tonic-gate  */
2213*7c478bd9Sstevel@tonic-gate int
2214*7c478bd9Sstevel@tonic-gate logint_upcount(struct phyint *pi)
2215*7c478bd9Sstevel@tonic-gate {
2216*7c478bd9Sstevel@tonic-gate 	struct	logint	*li;
2217*7c478bd9Sstevel@tonic-gate 	struct	phyint_instance *pii;
2218*7c478bd9Sstevel@tonic-gate 	int count = 0;
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate 	pii = pi->pi_v4;
2221*7c478bd9Sstevel@tonic-gate 	if (pii != NULL) {
2222*7c478bd9Sstevel@tonic-gate 		for (li = pii->pii_logint; li != NULL; li = li->li_next) {
2223*7c478bd9Sstevel@tonic-gate 			if ((li->li_flags &
2224*7c478bd9Sstevel@tonic-gate 			    (IFF_UP | IFF_NOFAILOVER)) == IFF_UP) {
2225*7c478bd9Sstevel@tonic-gate 				count++;
2226*7c478bd9Sstevel@tonic-gate 			}
2227*7c478bd9Sstevel@tonic-gate 		}
2228*7c478bd9Sstevel@tonic-gate 	}
2229*7c478bd9Sstevel@tonic-gate 
2230*7c478bd9Sstevel@tonic-gate 	pii = pi->pi_v6;
2231*7c478bd9Sstevel@tonic-gate 	if (pii != NULL) {
2232*7c478bd9Sstevel@tonic-gate 		for (li = pii->pii_logint; li != NULL; li = li->li_next) {
2233*7c478bd9Sstevel@tonic-gate 			if ((li->li_flags &
2234*7c478bd9Sstevel@tonic-gate 			    (IFF_UP | IFF_NOFAILOVER)) == IFF_UP) {
2235*7c478bd9Sstevel@tonic-gate 				count++;
2236*7c478bd9Sstevel@tonic-gate 			}
2237*7c478bd9Sstevel@tonic-gate 		}
2238*7c478bd9Sstevel@tonic-gate 	}
2239*7c478bd9Sstevel@tonic-gate 
2240*7c478bd9Sstevel@tonic-gate 	return (count);
2241*7c478bd9Sstevel@tonic-gate }
2242*7c478bd9Sstevel@tonic-gate 
2243*7c478bd9Sstevel@tonic-gate /*
2244*7c478bd9Sstevel@tonic-gate  * Get the phyint instance with the other (IPv4 / IPv6) protocol
2245*7c478bd9Sstevel@tonic-gate  */
2246*7c478bd9Sstevel@tonic-gate struct phyint_instance *
2247*7c478bd9Sstevel@tonic-gate phyint_inst_other(struct phyint_instance *pii)
2248*7c478bd9Sstevel@tonic-gate {
2249*7c478bd9Sstevel@tonic-gate 	if (pii->pii_af == AF_INET)
2250*7c478bd9Sstevel@tonic-gate 		return (pii->pii_phyint->pi_v6);
2251*7c478bd9Sstevel@tonic-gate 	else
2252*7c478bd9Sstevel@tonic-gate 		return (pii->pii_phyint->pi_v4);
2253*7c478bd9Sstevel@tonic-gate }
2254*7c478bd9Sstevel@tonic-gate 
2255*7c478bd9Sstevel@tonic-gate /*
2256*7c478bd9Sstevel@tonic-gate  * Post an EC_IPMP sysevent of subclass `subclass' and attributes `nvl'.
2257*7c478bd9Sstevel@tonic-gate  * Before sending the event, it prepends the current version of the IPMP
2258*7c478bd9Sstevel@tonic-gate  * sysevent API.  Returns 0 on success, -1 on failure (in either case,
2259*7c478bd9Sstevel@tonic-gate  * `nvl' is freed).
2260*7c478bd9Sstevel@tonic-gate  */
2261*7c478bd9Sstevel@tonic-gate static int
2262*7c478bd9Sstevel@tonic-gate post_event(const char *subclass, nvlist_t *nvl)
2263*7c478bd9Sstevel@tonic-gate {
2264*7c478bd9Sstevel@tonic-gate 	sysevent_id_t eid;
2265*7c478bd9Sstevel@tonic-gate 
2266*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_EVENT_VERSION,
2267*7c478bd9Sstevel@tonic-gate 	    IPMP_EVENT_CUR_VERSION);
2268*7c478bd9Sstevel@tonic-gate 	if (errno != 0) {
2269*7c478bd9Sstevel@tonic-gate 		logerr("cannot create `%s' event: %s", subclass,
2270*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
2271*7c478bd9Sstevel@tonic-gate 		goto failed;
2272*7c478bd9Sstevel@tonic-gate 	}
2273*7c478bd9Sstevel@tonic-gate 
2274*7c478bd9Sstevel@tonic-gate 	if (sysevent_post_event(EC_IPMP, (char *)subclass, SUNW_VENDOR,
2275*7c478bd9Sstevel@tonic-gate 	    "in.mpathd", nvl, &eid) == -1) {
2276*7c478bd9Sstevel@tonic-gate 		logerr("cannot send `%s' event: %s\n", subclass,
2277*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
2278*7c478bd9Sstevel@tonic-gate 		goto failed;
2279*7c478bd9Sstevel@tonic-gate 	}
2280*7c478bd9Sstevel@tonic-gate 
2281*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
2282*7c478bd9Sstevel@tonic-gate 	return (0);
2283*7c478bd9Sstevel@tonic-gate failed:
2284*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
2285*7c478bd9Sstevel@tonic-gate 	return (-1);
2286*7c478bd9Sstevel@tonic-gate }
2287*7c478bd9Sstevel@tonic-gate 
2288*7c478bd9Sstevel@tonic-gate /*
2289*7c478bd9Sstevel@tonic-gate  * Return the external IPMP state associated with phyint `pi'.
2290*7c478bd9Sstevel@tonic-gate  */
2291*7c478bd9Sstevel@tonic-gate static ipmp_if_state_t
2292*7c478bd9Sstevel@tonic-gate ifstate(struct phyint *pi)
2293*7c478bd9Sstevel@tonic-gate {
2294*7c478bd9Sstevel@tonic-gate 	switch (pi->pi_state) {
2295*7c478bd9Sstevel@tonic-gate 	case PI_NOTARGETS:
2296*7c478bd9Sstevel@tonic-gate 		return (IPMP_IF_UNKNOWN);
2297*7c478bd9Sstevel@tonic-gate 
2298*7c478bd9Sstevel@tonic-gate 	case PI_OFFLINE:
2299*7c478bd9Sstevel@tonic-gate 		return (IPMP_IF_OFFLINE);
2300*7c478bd9Sstevel@tonic-gate 
2301*7c478bd9Sstevel@tonic-gate 	case PI_FAILED:
2302*7c478bd9Sstevel@tonic-gate 		return (IPMP_IF_FAILED);
2303*7c478bd9Sstevel@tonic-gate 
2304*7c478bd9Sstevel@tonic-gate 	case PI_RUNNING:
2305*7c478bd9Sstevel@tonic-gate 		return (IPMP_IF_OK);
2306*7c478bd9Sstevel@tonic-gate 	}
2307*7c478bd9Sstevel@tonic-gate 
2308*7c478bd9Sstevel@tonic-gate 	logerr("ifstate: unknown state %d; aborting\n", pi->pi_state);
2309*7c478bd9Sstevel@tonic-gate 	abort();
2310*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
2311*7c478bd9Sstevel@tonic-gate }
2312*7c478bd9Sstevel@tonic-gate 
2313*7c478bd9Sstevel@tonic-gate /*
2314*7c478bd9Sstevel@tonic-gate  * Return the external IPMP interface type associated with phyint `pi'.
2315*7c478bd9Sstevel@tonic-gate  */
2316*7c478bd9Sstevel@tonic-gate static ipmp_if_type_t
2317*7c478bd9Sstevel@tonic-gate iftype(struct phyint *pi)
2318*7c478bd9Sstevel@tonic-gate {
2319*7c478bd9Sstevel@tonic-gate 	if (pi->pi_flags & IFF_STANDBY)
2320*7c478bd9Sstevel@tonic-gate 		return (IPMP_IF_STANDBY);
2321*7c478bd9Sstevel@tonic-gate 	else
2322*7c478bd9Sstevel@tonic-gate 		return (IPMP_IF_NORMAL);
2323*7c478bd9Sstevel@tonic-gate }
2324*7c478bd9Sstevel@tonic-gate 
2325*7c478bd9Sstevel@tonic-gate /*
2326*7c478bd9Sstevel@tonic-gate  * Return the external IPMP group state associated with phyint group `pg'.
2327*7c478bd9Sstevel@tonic-gate  */
2328*7c478bd9Sstevel@tonic-gate static ipmp_group_state_t
2329*7c478bd9Sstevel@tonic-gate groupstate(struct phyint_group *pg)
2330*7c478bd9Sstevel@tonic-gate {
2331*7c478bd9Sstevel@tonic-gate 	return (GROUP_FAILED(pg) ? IPMP_GROUP_FAILED : IPMP_GROUP_OK);
2332*7c478bd9Sstevel@tonic-gate }
2333*7c478bd9Sstevel@tonic-gate 
2334*7c478bd9Sstevel@tonic-gate /*
2335*7c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_GROUP_STATE sysevent for phyint group `pg'.
2336*7c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
2337*7c478bd9Sstevel@tonic-gate  */
2338*7c478bd9Sstevel@tonic-gate static int
2339*7c478bd9Sstevel@tonic-gate phyint_group_state_event(struct phyint_group *pg)
2340*7c478bd9Sstevel@tonic-gate {
2341*7c478bd9Sstevel@tonic-gate 	nvlist_t	*nvl;
2342*7c478bd9Sstevel@tonic-gate 
2343*7c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
2344*7c478bd9Sstevel@tonic-gate 	if (errno != 0) {
2345*7c478bd9Sstevel@tonic-gate 		logperror("cannot create `group state change' event");
2346*7c478bd9Sstevel@tonic-gate 		return (-1);
2347*7c478bd9Sstevel@tonic-gate 	}
2348*7c478bd9Sstevel@tonic-gate 
2349*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
2350*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2351*7c478bd9Sstevel@tonic-gate 		goto failed;
2352*7c478bd9Sstevel@tonic-gate 
2353*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
2354*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2355*7c478bd9Sstevel@tonic-gate 		goto failed;
2356*7c478bd9Sstevel@tonic-gate 
2357*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_GROUP_STATE, groupstate(pg));
2358*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2359*7c478bd9Sstevel@tonic-gate 		goto failed;
2360*7c478bd9Sstevel@tonic-gate 
2361*7c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_GROUP_STATE, nvl));
2362*7c478bd9Sstevel@tonic-gate failed:
2363*7c478bd9Sstevel@tonic-gate 	logperror("cannot create `group state change' event");
2364*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
2365*7c478bd9Sstevel@tonic-gate 	return (-1);
2366*7c478bd9Sstevel@tonic-gate }
2367*7c478bd9Sstevel@tonic-gate 
2368*7c478bd9Sstevel@tonic-gate /*
2369*7c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_GROUP_CHANGE sysevent of type `op' for phyint group
2370*7c478bd9Sstevel@tonic-gate  * `pg'.  Returns 0 on success, -1 on failure.
2371*7c478bd9Sstevel@tonic-gate  */
2372*7c478bd9Sstevel@tonic-gate static int
2373*7c478bd9Sstevel@tonic-gate phyint_group_change_event(struct phyint_group *pg, ipmp_group_op_t op)
2374*7c478bd9Sstevel@tonic-gate {
2375*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
2376*7c478bd9Sstevel@tonic-gate 
2377*7c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
2378*7c478bd9Sstevel@tonic-gate 	if (errno != 0) {
2379*7c478bd9Sstevel@tonic-gate 		logperror("cannot create `group change' event");
2380*7c478bd9Sstevel@tonic-gate 		return (-1);
2381*7c478bd9Sstevel@tonic-gate 	}
2382*7c478bd9Sstevel@tonic-gate 
2383*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
2384*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2385*7c478bd9Sstevel@tonic-gate 		goto failed;
2386*7c478bd9Sstevel@tonic-gate 
2387*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
2388*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2389*7c478bd9Sstevel@tonic-gate 		goto failed;
2390*7c478bd9Sstevel@tonic-gate 
2391*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUPLIST_SIGNATURE,
2392*7c478bd9Sstevel@tonic-gate 	    phyint_grouplistsig);
2393*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2394*7c478bd9Sstevel@tonic-gate 		goto failed;
2395*7c478bd9Sstevel@tonic-gate 
2396*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_GROUP_OPERATION, op);
2397*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2398*7c478bd9Sstevel@tonic-gate 		goto failed;
2399*7c478bd9Sstevel@tonic-gate 
2400*7c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_GROUP_CHANGE, nvl));
2401*7c478bd9Sstevel@tonic-gate failed:
2402*7c478bd9Sstevel@tonic-gate 	logperror("cannot create `group change' event");
2403*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
2404*7c478bd9Sstevel@tonic-gate 	return (-1);
2405*7c478bd9Sstevel@tonic-gate }
2406*7c478bd9Sstevel@tonic-gate 
2407*7c478bd9Sstevel@tonic-gate /*
2408*7c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_GROUP_MEMBER_CHANGE sysevent for phyint `pi' in
2409*7c478bd9Sstevel@tonic-gate  * group `pg'.	Returns 0 on success, -1 on failure.
2410*7c478bd9Sstevel@tonic-gate  */
2411*7c478bd9Sstevel@tonic-gate static int
2412*7c478bd9Sstevel@tonic-gate phyint_group_member_event(struct phyint_group *pg, struct phyint *pi,
2413*7c478bd9Sstevel@tonic-gate     ipmp_if_op_t op)
2414*7c478bd9Sstevel@tonic-gate {
2415*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
2416*7c478bd9Sstevel@tonic-gate 
2417*7c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
2418*7c478bd9Sstevel@tonic-gate 	if (errno != 0) {
2419*7c478bd9Sstevel@tonic-gate 		logperror("cannot create `group member change' event");
2420*7c478bd9Sstevel@tonic-gate 		return (-1);
2421*7c478bd9Sstevel@tonic-gate 	}
2422*7c478bd9Sstevel@tonic-gate 
2423*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
2424*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2425*7c478bd9Sstevel@tonic-gate 		goto failed;
2426*7c478bd9Sstevel@tonic-gate 
2427*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
2428*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2429*7c478bd9Sstevel@tonic-gate 		goto failed;
2430*7c478bd9Sstevel@tonic-gate 
2431*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_OPERATION, op);
2432*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2433*7c478bd9Sstevel@tonic-gate 		goto failed;
2434*7c478bd9Sstevel@tonic-gate 
2435*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_IF_NAME, pi->pi_name);
2436*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2437*7c478bd9Sstevel@tonic-gate 		goto failed;
2438*7c478bd9Sstevel@tonic-gate 
2439*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_TYPE, iftype(pi));
2440*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2441*7c478bd9Sstevel@tonic-gate 		goto failed;
2442*7c478bd9Sstevel@tonic-gate 
2443*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_STATE, ifstate(pi));
2444*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2445*7c478bd9Sstevel@tonic-gate 		goto failed;
2446*7c478bd9Sstevel@tonic-gate 
2447*7c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_GROUP_MEMBER_CHANGE, nvl));
2448*7c478bd9Sstevel@tonic-gate failed:
2449*7c478bd9Sstevel@tonic-gate 	logperror("cannot create `group member change' event");
2450*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
2451*7c478bd9Sstevel@tonic-gate 	return (-1);
2452*7c478bd9Sstevel@tonic-gate 
2453*7c478bd9Sstevel@tonic-gate }
2454*7c478bd9Sstevel@tonic-gate 
2455*7c478bd9Sstevel@tonic-gate /*
2456*7c478bd9Sstevel@tonic-gate  * Generate an ESC_IPMP_IF_CHANGE sysevent for phyint `pi' in group `pg'.
2457*7c478bd9Sstevel@tonic-gate  * Returns 0 on success, -1 on failure.
2458*7c478bd9Sstevel@tonic-gate  */
2459*7c478bd9Sstevel@tonic-gate static int
2460*7c478bd9Sstevel@tonic-gate phyint_state_event(struct phyint_group *pg, struct phyint *pi)
2461*7c478bd9Sstevel@tonic-gate {
2462*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
2463*7c478bd9Sstevel@tonic-gate 
2464*7c478bd9Sstevel@tonic-gate 	errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
2465*7c478bd9Sstevel@tonic-gate 	if (errno != 0) {
2466*7c478bd9Sstevel@tonic-gate 		logperror("cannot create `interface change' event");
2467*7c478bd9Sstevel@tonic-gate 		return (-1);
2468*7c478bd9Sstevel@tonic-gate 	}
2469*7c478bd9Sstevel@tonic-gate 
2470*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_GROUP_NAME, pg->pg_name);
2471*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2472*7c478bd9Sstevel@tonic-gate 		goto failed;
2473*7c478bd9Sstevel@tonic-gate 
2474*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint64(nvl, IPMP_GROUP_SIGNATURE, pg->pg_sig);
2475*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2476*7c478bd9Sstevel@tonic-gate 		goto failed;
2477*7c478bd9Sstevel@tonic-gate 
2478*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_string(nvl, IPMP_IF_NAME, pi->pi_name);
2479*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2480*7c478bd9Sstevel@tonic-gate 		goto failed;
2481*7c478bd9Sstevel@tonic-gate 
2482*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_TYPE, iftype(pi));
2483*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2484*7c478bd9Sstevel@tonic-gate 		goto failed;
2485*7c478bd9Sstevel@tonic-gate 
2486*7c478bd9Sstevel@tonic-gate 	errno = nvlist_add_uint32(nvl, IPMP_IF_STATE, ifstate(pi));
2487*7c478bd9Sstevel@tonic-gate 	if (errno != 0)
2488*7c478bd9Sstevel@tonic-gate 		goto failed;
2489*7c478bd9Sstevel@tonic-gate 
2490*7c478bd9Sstevel@tonic-gate 	return (post_event(ESC_IPMP_IF_CHANGE, nvl));
2491*7c478bd9Sstevel@tonic-gate failed:
2492*7c478bd9Sstevel@tonic-gate 	logperror("cannot create `interface change' event");
2493*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
2494*7c478bd9Sstevel@tonic-gate 	return (-1);
2495*7c478bd9Sstevel@tonic-gate 
2496*7c478bd9Sstevel@tonic-gate }
2497*7c478bd9Sstevel@tonic-gate 
2498*7c478bd9Sstevel@tonic-gate /*
2499*7c478bd9Sstevel@tonic-gate  * Generate a signature for use.  The signature is conceptually divided
2500*7c478bd9Sstevel@tonic-gate  * into two pieces: a random 16-bit "generation number" and a 48-bit
2501*7c478bd9Sstevel@tonic-gate  * monotonically increasing integer.  The generation number protects
2502*7c478bd9Sstevel@tonic-gate  * against stale updates to entities (e.g., IPMP groups) that have been
2503*7c478bd9Sstevel@tonic-gate  * deleted and since recreated.
2504*7c478bd9Sstevel@tonic-gate  */
2505*7c478bd9Sstevel@tonic-gate static uint64_t
2506*7c478bd9Sstevel@tonic-gate gensig(void)
2507*7c478bd9Sstevel@tonic-gate {
2508*7c478bd9Sstevel@tonic-gate 	static int seeded = 0;
2509*7c478bd9Sstevel@tonic-gate 
2510*7c478bd9Sstevel@tonic-gate 	if (seeded == 0) {
2511*7c478bd9Sstevel@tonic-gate 		srand48((long)gethrtime());
2512*7c478bd9Sstevel@tonic-gate 		seeded++;
2513*7c478bd9Sstevel@tonic-gate 	}
2514*7c478bd9Sstevel@tonic-gate 
2515*7c478bd9Sstevel@tonic-gate 	return ((uint64_t)lrand48() << 48 | 1);
2516*7c478bd9Sstevel@tonic-gate }
2517*7c478bd9Sstevel@tonic-gate 
2518*7c478bd9Sstevel@tonic-gate /*
2519*7c478bd9Sstevel@tonic-gate  * Store the information associated with group `grname' into a dynamically
2520*7c478bd9Sstevel@tonic-gate  * allocated structure pointed to by `*grinfopp'.  Returns an IPMP error code.
2521*7c478bd9Sstevel@tonic-gate  */
2522*7c478bd9Sstevel@tonic-gate unsigned int
2523*7c478bd9Sstevel@tonic-gate getgroupinfo(const char *grname, ipmp_groupinfo_t **grinfopp)
2524*7c478bd9Sstevel@tonic-gate {
2525*7c478bd9Sstevel@tonic-gate 	struct phyint_group	*pg;
2526*7c478bd9Sstevel@tonic-gate 	struct phyint		*pi;
2527*7c478bd9Sstevel@tonic-gate 	char			(*ifs)[LIFNAMSIZ];
2528*7c478bd9Sstevel@tonic-gate 	unsigned int		nif, i;
2529*7c478bd9Sstevel@tonic-gate 
2530*7c478bd9Sstevel@tonic-gate 	pg = phyint_group_lookup(grname);
2531*7c478bd9Sstevel@tonic-gate 	if (pg == NULL)
2532*7c478bd9Sstevel@tonic-gate 		return (IPMP_EUNKGROUP);
2533*7c478bd9Sstevel@tonic-gate 
2534*7c478bd9Sstevel@tonic-gate 	/*
2535*7c478bd9Sstevel@tonic-gate 	 * Tally up the number of interfaces, allocate an array to hold them,
2536*7c478bd9Sstevel@tonic-gate 	 * and insert their names into the array.
2537*7c478bd9Sstevel@tonic-gate 	 */
2538*7c478bd9Sstevel@tonic-gate 	for (nif = 0, pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext)
2539*7c478bd9Sstevel@tonic-gate 		nif++;
2540*7c478bd9Sstevel@tonic-gate 
2541*7c478bd9Sstevel@tonic-gate 	ifs = alloca(nif * sizeof (*ifs));
2542*7c478bd9Sstevel@tonic-gate 	for (i = 0, pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext, i++) {
2543*7c478bd9Sstevel@tonic-gate 		assert(i < nif);
2544*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(ifs[i], pi->pi_name, LIFNAMSIZ);
2545*7c478bd9Sstevel@tonic-gate 	}
2546*7c478bd9Sstevel@tonic-gate 	assert(i == nif);
2547*7c478bd9Sstevel@tonic-gate 
2548*7c478bd9Sstevel@tonic-gate 	*grinfopp = ipmp_groupinfo_create(pg->pg_name, pg->pg_sig,
2549*7c478bd9Sstevel@tonic-gate 	    groupstate(pg), nif, ifs);
2550*7c478bd9Sstevel@tonic-gate 	return (*grinfopp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
2551*7c478bd9Sstevel@tonic-gate }
2552*7c478bd9Sstevel@tonic-gate 
2553*7c478bd9Sstevel@tonic-gate /*
2554*7c478bd9Sstevel@tonic-gate  * Store the information associated with interface `ifname' into a dynamically
2555*7c478bd9Sstevel@tonic-gate  * allocated structure pointed to by `*ifinfopp'.  Returns an IPMP error code.
2556*7c478bd9Sstevel@tonic-gate  */
2557*7c478bd9Sstevel@tonic-gate unsigned int
2558*7c478bd9Sstevel@tonic-gate getifinfo(const char *ifname, ipmp_ifinfo_t **ifinfopp)
2559*7c478bd9Sstevel@tonic-gate {
2560*7c478bd9Sstevel@tonic-gate 	struct phyint	*pi;
2561*7c478bd9Sstevel@tonic-gate 
2562*7c478bd9Sstevel@tonic-gate 	pi = phyint_lookup(ifname);
2563*7c478bd9Sstevel@tonic-gate 	if (pi == NULL)
2564*7c478bd9Sstevel@tonic-gate 		return (IPMP_EUNKIF);
2565*7c478bd9Sstevel@tonic-gate 
2566*7c478bd9Sstevel@tonic-gate 	*ifinfopp = ipmp_ifinfo_create(pi->pi_name, pi->pi_group->pg_name,
2567*7c478bd9Sstevel@tonic-gate 	    ifstate(pi), iftype(pi));
2568*7c478bd9Sstevel@tonic-gate 	return (*ifinfopp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
2569*7c478bd9Sstevel@tonic-gate }
2570*7c478bd9Sstevel@tonic-gate 
2571*7c478bd9Sstevel@tonic-gate /*
2572*7c478bd9Sstevel@tonic-gate  * Store the current list of IPMP groups into a dynamically allocated
2573*7c478bd9Sstevel@tonic-gate  * structure pointed to by `*grlistpp'.	 Returns an IPMP error code.
2574*7c478bd9Sstevel@tonic-gate  */
2575*7c478bd9Sstevel@tonic-gate unsigned int
2576*7c478bd9Sstevel@tonic-gate getgrouplist(ipmp_grouplist_t **grlistpp)
2577*7c478bd9Sstevel@tonic-gate {
2578*7c478bd9Sstevel@tonic-gate 	struct phyint_group	*pg;
2579*7c478bd9Sstevel@tonic-gate 	char			(*groups)[LIFGRNAMSIZ];
2580*7c478bd9Sstevel@tonic-gate 	unsigned int		i, ngroup;
2581*7c478bd9Sstevel@tonic-gate 
2582*7c478bd9Sstevel@tonic-gate 	/*
2583*7c478bd9Sstevel@tonic-gate 	 * Tally up the number of groups, allocate an array to hold them, and
2584*7c478bd9Sstevel@tonic-gate 	 * insert their names into the array.
2585*7c478bd9Sstevel@tonic-gate 	 */
2586*7c478bd9Sstevel@tonic-gate 	for (ngroup = 0, pg = phyint_groups; pg != NULL; pg = pg->pg_next)
2587*7c478bd9Sstevel@tonic-gate 		ngroup++;
2588*7c478bd9Sstevel@tonic-gate 
2589*7c478bd9Sstevel@tonic-gate 	groups = alloca(ngroup * sizeof (*groups));
2590*7c478bd9Sstevel@tonic-gate 	for (i = 0, pg = phyint_groups; pg != NULL; pg = pg->pg_next, i++) {
2591*7c478bd9Sstevel@tonic-gate 		assert(i < ngroup);
2592*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(groups[i], pg->pg_name, LIFGRNAMSIZ);
2593*7c478bd9Sstevel@tonic-gate 	}
2594*7c478bd9Sstevel@tonic-gate 	assert(i == ngroup);
2595*7c478bd9Sstevel@tonic-gate 
2596*7c478bd9Sstevel@tonic-gate 	*grlistpp = ipmp_grouplist_create(phyint_grouplistsig, ngroup, groups);
2597*7c478bd9Sstevel@tonic-gate 	return (*grlistpp == NULL ? IPMP_ENOMEM : IPMP_SUCCESS);
2598*7c478bd9Sstevel@tonic-gate }
2599*7c478bd9Sstevel@tonic-gate 
2600*7c478bd9Sstevel@tonic-gate /*
2601*7c478bd9Sstevel@tonic-gate  * Store a snapshot of the IPMP subsystem into a dynamically allocated
2602*7c478bd9Sstevel@tonic-gate  * structure pointed to by `*snapp'.  Returns an IPMP error code.
2603*7c478bd9Sstevel@tonic-gate  */
2604*7c478bd9Sstevel@tonic-gate unsigned int
2605*7c478bd9Sstevel@tonic-gate getsnap(ipmp_snap_t **snapp)
2606*7c478bd9Sstevel@tonic-gate {
2607*7c478bd9Sstevel@tonic-gate 	ipmp_grouplist_t	*grlistp;
2608*7c478bd9Sstevel@tonic-gate 	ipmp_groupinfo_t	*grinfop;
2609*7c478bd9Sstevel@tonic-gate 	ipmp_ifinfo_t		*ifinfop;
2610*7c478bd9Sstevel@tonic-gate 	ipmp_snap_t		*snap;
2611*7c478bd9Sstevel@tonic-gate 	struct phyint		*pi;
2612*7c478bd9Sstevel@tonic-gate 	unsigned int		i;
2613*7c478bd9Sstevel@tonic-gate 	int			retval;
2614*7c478bd9Sstevel@tonic-gate 
2615*7c478bd9Sstevel@tonic-gate 	snap = ipmp_snap_create();
2616*7c478bd9Sstevel@tonic-gate 	if (snap == NULL)
2617*7c478bd9Sstevel@tonic-gate 		return (IPMP_ENOMEM);
2618*7c478bd9Sstevel@tonic-gate 
2619*7c478bd9Sstevel@tonic-gate 	/*
2620*7c478bd9Sstevel@tonic-gate 	 * Add group list.
2621*7c478bd9Sstevel@tonic-gate 	 */
2622*7c478bd9Sstevel@tonic-gate 	retval = getgrouplist(&snap->sn_grlistp);
2623*7c478bd9Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS) {
2624*7c478bd9Sstevel@tonic-gate 		ipmp_snap_free(snap);
2625*7c478bd9Sstevel@tonic-gate 		return (retval);
2626*7c478bd9Sstevel@tonic-gate 	}
2627*7c478bd9Sstevel@tonic-gate 
2628*7c478bd9Sstevel@tonic-gate 	/*
2629*7c478bd9Sstevel@tonic-gate 	 * Add information for each group in the list.
2630*7c478bd9Sstevel@tonic-gate 	 */
2631*7c478bd9Sstevel@tonic-gate 	grlistp = snap->sn_grlistp;
2632*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < grlistp->gl_ngroup; i++) {
2633*7c478bd9Sstevel@tonic-gate 		retval = getgroupinfo(grlistp->gl_groups[i], &grinfop);
2634*7c478bd9Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
2635*7c478bd9Sstevel@tonic-gate 			ipmp_snap_free(snap);
2636*7c478bd9Sstevel@tonic-gate 			return (retval);
2637*7c478bd9Sstevel@tonic-gate 		}
2638*7c478bd9Sstevel@tonic-gate 		retval = ipmp_snap_addgroupinfo(snap, grinfop);
2639*7c478bd9Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
2640*7c478bd9Sstevel@tonic-gate 			ipmp_freegroupinfo(grinfop);
2641*7c478bd9Sstevel@tonic-gate 			ipmp_snap_free(snap);
2642*7c478bd9Sstevel@tonic-gate 			return (retval);
2643*7c478bd9Sstevel@tonic-gate 		}
2644*7c478bd9Sstevel@tonic-gate 	}
2645*7c478bd9Sstevel@tonic-gate 
2646*7c478bd9Sstevel@tonic-gate 	/*
2647*7c478bd9Sstevel@tonic-gate 	 * Add information for each configured phyint.
2648*7c478bd9Sstevel@tonic-gate 	 */
2649*7c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
2650*7c478bd9Sstevel@tonic-gate 		retval = getifinfo(pi->pi_name, &ifinfop);
2651*7c478bd9Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
2652*7c478bd9Sstevel@tonic-gate 			ipmp_snap_free(snap);
2653*7c478bd9Sstevel@tonic-gate 			return (retval);
2654*7c478bd9Sstevel@tonic-gate 		}
2655*7c478bd9Sstevel@tonic-gate 		retval = ipmp_snap_addifinfo(snap, ifinfop);
2656*7c478bd9Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
2657*7c478bd9Sstevel@tonic-gate 			ipmp_freeifinfo(ifinfop);
2658*7c478bd9Sstevel@tonic-gate 			ipmp_snap_free(snap);
2659*7c478bd9Sstevel@tonic-gate 			return (retval);
2660*7c478bd9Sstevel@tonic-gate 		}
2661*7c478bd9Sstevel@tonic-gate 	}
2662*7c478bd9Sstevel@tonic-gate 
2663*7c478bd9Sstevel@tonic-gate 	*snapp = snap;
2664*7c478bd9Sstevel@tonic-gate 	return (IPMP_SUCCESS);
2665*7c478bd9Sstevel@tonic-gate }
2666