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 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 * 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 * 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 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 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 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 * 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 * 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 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 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 * 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 * 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 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 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 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 * 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 * 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 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 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 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 * 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 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 * 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 * 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 * 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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