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