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