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