17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5921e7e07Smeem * Common Development and Distribution License (the "License"). 6921e7e07Smeem * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22e11c3f44Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include "mpd_defs.h" 277c478bd9Sstevel@tonic-gate #include "mpd_tables.h" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate int debug = 0; /* Debug flag */ 307c478bd9Sstevel@tonic-gate static int pollfd_num = 0; /* Num. of poll descriptors */ 317c478bd9Sstevel@tonic-gate static struct pollfd *pollfds = NULL; /* Array of poll descriptors */ 327c478bd9Sstevel@tonic-gate /* All times below in ms */ 337c478bd9Sstevel@tonic-gate int user_failure_detection_time; /* user specified failure detection */ 347c478bd9Sstevel@tonic-gate /* time (fdt) */ 357c478bd9Sstevel@tonic-gate int user_probe_interval; /* derived from user specified fdt */ 367c478bd9Sstevel@tonic-gate 3727438c18SJon Anderson /* 3827438c18SJon Anderson * Structure to store mib2 information returned by the kernel. 3927438c18SJon Anderson * This is used to process routing table information. 4027438c18SJon Anderson */ 4127438c18SJon Anderson typedef struct mib_item_s { 4227438c18SJon Anderson struct mib_item_s *mi_next; 4327438c18SJon Anderson struct opthdr mi_opthdr; 4427438c18SJon Anderson void *mi_valp; 4527438c18SJon Anderson } mib_item_t; 4627438c18SJon Anderson 477c478bd9Sstevel@tonic-gate static int rtsock_v4; /* AF_INET routing socket */ 487c478bd9Sstevel@tonic-gate static int rtsock_v6; /* AF_INET6 routing socket */ 497c478bd9Sstevel@tonic-gate int ifsock_v4 = -1; /* IPv4 socket for ioctls */ 507c478bd9Sstevel@tonic-gate int ifsock_v6 = -1; /* IPv6 socket for ioctls */ 517c478bd9Sstevel@tonic-gate static int lsock_v4; /* Listen socket to detect mpathd */ 527c478bd9Sstevel@tonic-gate static int lsock_v6; /* Listen socket to detect mpathd */ 537c478bd9Sstevel@tonic-gate static int mibfd = -1; /* fd to get mib info */ 547c478bd9Sstevel@tonic-gate static boolean_t force_mcast = _B_FALSE; /* Only for test purposes */ 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate static uint_t last_initifs_time; /* Time when initifs was last run */ 577c478bd9Sstevel@tonic-gate static char **argv0; /* Saved for re-exec on SIGHUP */ 587c478bd9Sstevel@tonic-gate boolean_t handle_link_notifications = _B_TRUE; 5927438c18SJon Anderson static int ipRouteEntrySize; /* Size of IPv4 route entry */ 6027438c18SJon Anderson static int ipv6RouteEntrySize; /* Size of IPv6 route entry */ 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate static void initlog(void); 637c478bd9Sstevel@tonic-gate static void run_timeouts(void); 647c478bd9Sstevel@tonic-gate static void initifs(void); 657c478bd9Sstevel@tonic-gate static void check_if_removed(struct phyint_instance *pii); 667c478bd9Sstevel@tonic-gate static void select_test_ifs(void); 6727438c18SJon Anderson static void update_router_list(mib_item_t *item); 6827438c18SJon Anderson static void mib_get_constants(mib_item_t *item); 6927438c18SJon Anderson static int mibwalk(void (*proc)(mib_item_t *)); 707c478bd9Sstevel@tonic-gate static void ire_process_v4(mib2_ipRouteEntry_t *buf, size_t len); 717c478bd9Sstevel@tonic-gate static void ire_process_v6(mib2_ipv6RouteEntry_t *buf, size_t len); 727c478bd9Sstevel@tonic-gate static void router_add_common(int af, char *ifname, 737c478bd9Sstevel@tonic-gate struct in6_addr nexthop); 747c478bd9Sstevel@tonic-gate static void init_router_targets(); 757c478bd9Sstevel@tonic-gate static void cleanup(void); 767c478bd9Sstevel@tonic-gate static int setup_listener(int af); 777c478bd9Sstevel@tonic-gate static void check_config(void); 78e6ed03fcSmeem static void check_testconfig(void); 7906cdd167Smeem static void check_addr_unique(struct phyint_instance *, 8006cdd167Smeem struct sockaddr_storage *); 817c478bd9Sstevel@tonic-gate static void init_host_targets(void); 827c478bd9Sstevel@tonic-gate static void dup_host_targets(struct phyint_instance *desired_pii); 837c478bd9Sstevel@tonic-gate static void loopback_cmd(int sock, int family); 847c478bd9Sstevel@tonic-gate static boolean_t daemonize(void); 857c478bd9Sstevel@tonic-gate static int closefunc(void *, int); 867c478bd9Sstevel@tonic-gate static unsigned int process_cmd(int newfd, union mi_commands *mpi); 877c478bd9Sstevel@tonic-gate static unsigned int process_query(int fd, mi_query_t *miq); 88e11c3f44Smeem static unsigned int send_addrinfo(int fd, ipmp_addrinfo_t *adinfop); 897c478bd9Sstevel@tonic-gate static unsigned int send_groupinfo(int fd, ipmp_groupinfo_t *grinfop); 907c478bd9Sstevel@tonic-gate static unsigned int send_grouplist(int fd, ipmp_grouplist_t *grlistp); 917c478bd9Sstevel@tonic-gate static unsigned int send_ifinfo(int fd, ipmp_ifinfo_t *ifinfop); 927c478bd9Sstevel@tonic-gate static unsigned int send_result(int fd, unsigned int error, int syserror); 937c478bd9Sstevel@tonic-gate 94e11c3f44Smeem addrlist_t *localaddrs; 9587e66ffcSrk129064 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * Return the current time in milliseconds (from an arbitrary reference) 987c478bd9Sstevel@tonic-gate * truncated to fit into an int. Truncation is ok since we are interested 997c478bd9Sstevel@tonic-gate * only in differences and not the absolute values. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate uint_t 1027c478bd9Sstevel@tonic-gate getcurrenttime(void) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate uint_t cur_time; /* In ms */ 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * Use of a non-user-adjustable source of time is 1087c478bd9Sstevel@tonic-gate * required. However millisecond precision is sufficient. 1097c478bd9Sstevel@tonic-gate * divide by 10^6 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate cur_time = (uint_t)(gethrtime() / 1000000LL); 1127c478bd9Sstevel@tonic-gate return (cur_time); 1137c478bd9Sstevel@tonic-gate } 1147c478bd9Sstevel@tonic-gate 115e6ed03fcSmeem uint64_t 116e6ed03fcSmeem getcurrentsec(void) 117e6ed03fcSmeem { 118e6ed03fcSmeem return (gethrtime() / NANOSEC); 119e6ed03fcSmeem } 120e6ed03fcSmeem 1217c478bd9Sstevel@tonic-gate /* 1227c478bd9Sstevel@tonic-gate * Add fd to the set being polled. Returns 0 if ok; -1 if failed. 1237c478bd9Sstevel@tonic-gate */ 1247c478bd9Sstevel@tonic-gate int 1257c478bd9Sstevel@tonic-gate poll_add(int fd) 1267c478bd9Sstevel@tonic-gate { 1277c478bd9Sstevel@tonic-gate int i; 1287c478bd9Sstevel@tonic-gate int new_num; 1297c478bd9Sstevel@tonic-gate struct pollfd *newfds; 1307c478bd9Sstevel@tonic-gate retry: 1317c478bd9Sstevel@tonic-gate /* Check if already present */ 1327c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 1337c478bd9Sstevel@tonic-gate if (pollfds[i].fd == fd) 1347c478bd9Sstevel@tonic-gate return (0); 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate /* Check for empty spot already present */ 1377c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 1387c478bd9Sstevel@tonic-gate if (pollfds[i].fd == -1) { 1397c478bd9Sstevel@tonic-gate pollfds[i].fd = fd; 1407c478bd9Sstevel@tonic-gate return (0); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /* Allocate space for 32 more fds and initialize to -1 */ 1457c478bd9Sstevel@tonic-gate new_num = pollfd_num + 32; 1467c478bd9Sstevel@tonic-gate newfds = realloc(pollfds, new_num * sizeof (struct pollfd)); 1477c478bd9Sstevel@tonic-gate if (newfds == NULL) { 1487c478bd9Sstevel@tonic-gate logperror("poll_add: realloc"); 1497c478bd9Sstevel@tonic-gate return (-1); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate for (i = pollfd_num; i < new_num; i++) { 1527c478bd9Sstevel@tonic-gate newfds[i].fd = -1; 1537c478bd9Sstevel@tonic-gate newfds[i].events = POLLIN; 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate pollfd_num = new_num; 1567c478bd9Sstevel@tonic-gate pollfds = newfds; 1577c478bd9Sstevel@tonic-gate goto retry; 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * Remove fd from the set being polled. Returns 0 if ok; -1 if failed. 1627c478bd9Sstevel@tonic-gate */ 163e11c3f44Smeem int 1647c478bd9Sstevel@tonic-gate poll_remove(int fd) 1657c478bd9Sstevel@tonic-gate { 1667c478bd9Sstevel@tonic-gate int i; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* Check if already present */ 1697c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 1707c478bd9Sstevel@tonic-gate if (pollfds[i].fd == fd) { 1717c478bd9Sstevel@tonic-gate pollfds[i].fd = -1; 1727c478bd9Sstevel@tonic-gate return (0); 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate return (-1); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate /* 1797c478bd9Sstevel@tonic-gate * Extract information about the phyint instance. If the phyint instance still 1807c478bd9Sstevel@tonic-gate * exists in the kernel then set pii_in_use, else clear it. check_if_removed() 1817c478bd9Sstevel@tonic-gate * will use it to detect phyint instances that don't exist any longer and 1827c478bd9Sstevel@tonic-gate * remove them, from our database of phyint instances. 1837c478bd9Sstevel@tonic-gate * Return value: 1847c478bd9Sstevel@tonic-gate * returns true if the phyint instance exists in the kernel, 1857c478bd9Sstevel@tonic-gate * returns false otherwise 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate static boolean_t 1887c478bd9Sstevel@tonic-gate pii_process(int af, char *name, struct phyint_instance **pii_p) 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate int err; 1917c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 1927c478bd9Sstevel@tonic-gate struct phyint_instance *pii_other; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) 1957c478bd9Sstevel@tonic-gate logdebug("pii_process(%s %s)\n", AF_STR(af), name); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate pii = phyint_inst_lookup(af, name); 1987c478bd9Sstevel@tonic-gate if (pii == NULL) { 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * Phyint instance does not exist in our tables, 2017c478bd9Sstevel@tonic-gate * create new phyint instance 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate pii = phyint_inst_init_from_k(af, name); 2047c478bd9Sstevel@tonic-gate } else { 2057c478bd9Sstevel@tonic-gate /* Phyint exists in our tables */ 2067c478bd9Sstevel@tonic-gate err = phyint_inst_update_from_k(pii); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate switch (err) { 2097c478bd9Sstevel@tonic-gate case PI_IOCTL_ERROR: 2107c478bd9Sstevel@tonic-gate /* Some ioctl error. don't change anything */ 2117c478bd9Sstevel@tonic-gate pii->pii_in_use = 1; 2127c478bd9Sstevel@tonic-gate break; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate case PI_GROUP_CHANGED: 2157c478bd9Sstevel@tonic-gate case PI_IFINDEX_CHANGED: 2167c478bd9Sstevel@tonic-gate /* 217e11c3f44Smeem * Interface index or group membership has changed. 218e11c3f44Smeem * Delete the old state and recreate based on the new 219e11c3f44Smeem * state (it may no longer be in a group). 2207c478bd9Sstevel@tonic-gate */ 2217c478bd9Sstevel@tonic-gate pii_other = phyint_inst_other(pii); 2227c478bd9Sstevel@tonic-gate if (pii_other != NULL) 2237c478bd9Sstevel@tonic-gate phyint_inst_delete(pii_other); 2247c478bd9Sstevel@tonic-gate phyint_inst_delete(pii); 2257c478bd9Sstevel@tonic-gate pii = phyint_inst_init_from_k(af, name); 2267c478bd9Sstevel@tonic-gate break; 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate case PI_DELETED: 2297c478bd9Sstevel@tonic-gate /* Phyint instance has disappeared from kernel */ 2307c478bd9Sstevel@tonic-gate pii->pii_in_use = 0; 2317c478bd9Sstevel@tonic-gate break; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate case PI_OK: 2347c478bd9Sstevel@tonic-gate /* Phyint instance exists and is fine */ 2357c478bd9Sstevel@tonic-gate pii->pii_in_use = 1; 2367c478bd9Sstevel@tonic-gate break; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate default: 2397c478bd9Sstevel@tonic-gate /* Unknown status */ 2407c478bd9Sstevel@tonic-gate logerr("pii_process: Unknown status %d\n", err); 2417c478bd9Sstevel@tonic-gate break; 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate *pii_p = pii; 2467c478bd9Sstevel@tonic-gate if (pii != NULL) 2477c478bd9Sstevel@tonic-gate return (pii->pii_in_use ? _B_TRUE : _B_FALSE); 2487c478bd9Sstevel@tonic-gate else 2497c478bd9Sstevel@tonic-gate return (_B_FALSE); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * Scan all interfaces to detect changes as well as new and deleted interfaces 2547c478bd9Sstevel@tonic-gate */ 2557c478bd9Sstevel@tonic-gate static void 2567c478bd9Sstevel@tonic-gate initifs() 2577c478bd9Sstevel@tonic-gate { 258e11c3f44Smeem int i, nlifr; 2597c478bd9Sstevel@tonic-gate int af; 2607c478bd9Sstevel@tonic-gate char *cp; 2617c478bd9Sstevel@tonic-gate char *buf; 262e11c3f44Smeem int sockfd; 263e11c3f44Smeem uint64_t flags; 2647c478bd9Sstevel@tonic-gate struct lifnum lifn; 2657c478bd9Sstevel@tonic-gate struct lifconf lifc; 266e11c3f44Smeem struct lifreq lifreq; 2677c478bd9Sstevel@tonic-gate struct lifreq *lifr; 2687c478bd9Sstevel@tonic-gate struct logint *li; 2697c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 2707c478bd9Sstevel@tonic-gate struct phyint_instance *next_pii; 271e11c3f44Smeem struct phyint_group *pg, *next_pg; 2727c478bd9Sstevel@tonic-gate char pi_name[LIFNAMSIZ + 1]; 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) 2757c478bd9Sstevel@tonic-gate logdebug("initifs: Scanning interfaces\n"); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate last_initifs_time = getcurrenttime(); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 280e11c3f44Smeem * Free the existing local address list; we'll build a new list below. 28187e66ffcSrk129064 */ 282e11c3f44Smeem addrlist_free(&localaddrs); 28387e66ffcSrk129064 28487e66ffcSrk129064 /* 2857c478bd9Sstevel@tonic-gate * Mark the interfaces so that we can find phyints and logints 2867c478bd9Sstevel@tonic-gate * which have disappeared from the kernel. pii_process() and 2877c478bd9Sstevel@tonic-gate * logint_init_from_k() will set {pii,li}_in_use when they find 2887c478bd9Sstevel@tonic-gate * the interface in the kernel. Also, clear dupaddr bit on probe 2897c478bd9Sstevel@tonic-gate * logint. check_addr_unique() will set the dupaddr bit on the 2907c478bd9Sstevel@tonic-gate * probe logint, if the testaddress is not unique. 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) { 2937c478bd9Sstevel@tonic-gate pii->pii_in_use = 0; 2947c478bd9Sstevel@tonic-gate for (li = pii->pii_logint; li != NULL; li = li->li_next) { 2957c478bd9Sstevel@tonic-gate li->li_in_use = 0; 2967c478bd9Sstevel@tonic-gate if (pii->pii_probe_logint == li) 2977c478bd9Sstevel@tonic-gate li->li_dupaddr = 0; 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 301e11c3f44Smeem /* 302e11c3f44Smeem * As above, mark groups so that we can detect IPMP interfaces which 303e11c3f44Smeem * have been removed from the kernel. Also, delete the group address 304e11c3f44Smeem * list since we'll iteratively recreate it below. 305e11c3f44Smeem */ 306e11c3f44Smeem for (pg = phyint_groups; pg != NULL; pg = pg->pg_next) { 307e11c3f44Smeem pg->pg_in_use = _B_FALSE; 308e11c3f44Smeem addrlist_free(&pg->pg_addrs); 309e11c3f44Smeem } 310e11c3f44Smeem 3117c478bd9Sstevel@tonic-gate lifn.lifn_family = AF_UNSPEC; 312e11c3f44Smeem lifn.lifn_flags = LIFC_ALLZONES | LIFC_UNDER_IPMP; 313e11c3f44Smeem again: 3147c478bd9Sstevel@tonic-gate if (ioctl(ifsock_v4, SIOCGLIFNUM, (char *)&lifn) < 0) { 315e11c3f44Smeem logperror("initifs: ioctl (get interface count)"); 3167c478bd9Sstevel@tonic-gate return; 3177c478bd9Sstevel@tonic-gate } 318e11c3f44Smeem /* 319e11c3f44Smeem * Pad the interface count to detect when additional interfaces have 320e11c3f44Smeem * been configured between SIOCGLIFNUM and SIOCGLIFCONF. 321e11c3f44Smeem */ 322e11c3f44Smeem lifn.lifn_count += 4; 3237c478bd9Sstevel@tonic-gate 324e11c3f44Smeem if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) { 3257c478bd9Sstevel@tonic-gate logperror("initifs: calloc"); 3267c478bd9Sstevel@tonic-gate return; 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate lifc.lifc_family = AF_UNSPEC; 330e11c3f44Smeem lifc.lifc_flags = LIFC_ALLZONES | LIFC_UNDER_IPMP; 331e11c3f44Smeem lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 3327c478bd9Sstevel@tonic-gate lifc.lifc_buf = buf; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate if (ioctl(ifsock_v4, SIOCGLIFCONF, (char *)&lifc) < 0) { 335e11c3f44Smeem logperror("initifs: ioctl (get interface configuration)"); 3367c478bd9Sstevel@tonic-gate free(buf); 3377c478bd9Sstevel@tonic-gate return; 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 340e11c3f44Smeem /* 341e11c3f44Smeem * If every lifr_req slot is taken, then additional interfaces must 342e11c3f44Smeem * have been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF. 343e11c3f44Smeem * Recalculate to make sure we didn't miss any interfaces. 344e11c3f44Smeem */ 345e11c3f44Smeem nlifr = lifc.lifc_len / sizeof (struct lifreq); 346e11c3f44Smeem if (nlifr >= lifn.lifn_count) { 347e11c3f44Smeem free(buf); 348e11c3f44Smeem goto again; 349e11c3f44Smeem } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 352e11c3f44Smeem * Walk through the lifreqs returned by SIOGGLIFCONF, and refresh the 353e11c3f44Smeem * global list of addresses, phyint groups, phyints, and logints. 3547c478bd9Sstevel@tonic-gate */ 355e11c3f44Smeem for (lifr = lifc.lifc_req, i = 0; i < nlifr; i++, lifr++) { 3567c478bd9Sstevel@tonic-gate af = lifr->lifr_addr.ss_family; 35787e66ffcSrk129064 sockfd = (af == AF_INET) ? ifsock_v4 : ifsock_v6; 358e11c3f44Smeem (void) strlcpy(lifreq.lifr_name, lifr->lifr_name, LIFNAMSIZ); 35987e66ffcSrk129064 36087e66ffcSrk129064 if (ioctl(sockfd, SIOCGLIFFLAGS, &lifreq) == -1) { 36187e66ffcSrk129064 if (errno != ENXIO) 36287e66ffcSrk129064 logperror("initifs: ioctl (SIOCGLIFFLAGS)"); 36387e66ffcSrk129064 continue; 36487e66ffcSrk129064 } 365e11c3f44Smeem flags = lifreq.lifr_flags; 36687e66ffcSrk129064 36787e66ffcSrk129064 /* 368e11c3f44Smeem * If the address is IFF_UP, add it to the local address list. 369e11c3f44Smeem * (We ignore addresses that aren't IFF_UP since another node 370e11c3f44Smeem * might legitimately have that address IFF_UP.) 37187e66ffcSrk129064 */ 372e11c3f44Smeem if (flags & IFF_UP) { 373e11c3f44Smeem (void) addrlist_add(&localaddrs, lifr->lifr_name, flags, 374e11c3f44Smeem &lifr->lifr_addr); 375e11c3f44Smeem } 376e11c3f44Smeem 377e11c3f44Smeem /* 378e11c3f44Smeem * If this address is on an IPMP meta-interface, update our 379e11c3f44Smeem * phyint_group information (either by recording that group 380e11c3f44Smeem * still exists or creating a new group), and track what 381e11c3f44Smeem * group the address is part of. 382e11c3f44Smeem */ 383e11c3f44Smeem if (flags & IFF_IPMP) { 384e11c3f44Smeem if (ioctl(sockfd, SIOCGLIFGROUPNAME, &lifreq) == -1) { 385e11c3f44Smeem if (errno != ENXIO) 386e11c3f44Smeem logperror("initifs: ioctl " 387e11c3f44Smeem "(SIOCGLIFGROUPNAME)"); 38887e66ffcSrk129064 continue; 38987e66ffcSrk129064 } 390e11c3f44Smeem 391e11c3f44Smeem pg = phyint_group_lookup(lifreq.lifr_groupname); 392e11c3f44Smeem if (pg == NULL) { 393e11c3f44Smeem pg = phyint_group_create(lifreq.lifr_groupname); 394e11c3f44Smeem if (pg == NULL) { 395e11c3f44Smeem logerr("initifs: cannot create group " 396e11c3f44Smeem "%s\n", lifreq.lifr_groupname); 397e11c3f44Smeem continue; 39887e66ffcSrk129064 } 399e11c3f44Smeem phyint_group_insert(pg); 400e11c3f44Smeem } 401e11c3f44Smeem pg->pg_in_use = _B_TRUE; 402e11c3f44Smeem 403e11c3f44Smeem /* 404e11c3f44Smeem * Add this to the group's list of data addresses. 405e11c3f44Smeem */ 406e11c3f44Smeem if (!addrlist_add(&pg->pg_addrs, lifr->lifr_name, flags, 407e11c3f44Smeem &lifr->lifr_addr)) { 408e11c3f44Smeem logerr("initifs: insufficient memory to track " 409e11c3f44Smeem "data address information for %s\n", 410e11c3f44Smeem lifr->lifr_name); 411e11c3f44Smeem } 412e11c3f44Smeem continue; 41387e66ffcSrk129064 } 41487e66ffcSrk129064 41587e66ffcSrk129064 /* 416e11c3f44Smeem * This isn't an address on an IPMP meta-interface, so it's 417e11c3f44Smeem * either on an underlying interface or not related to any 418e11c3f44Smeem * group. Update our phyint and logint information (via 419e11c3f44Smeem * pii_process() and logint_init_from_k()) -- but first, 420e11c3f44Smeem * convert the logint name to a phyint name so we can call 421e11c3f44Smeem * pii_process(). 4227c478bd9Sstevel@tonic-gate */ 42387e66ffcSrk129064 (void) strlcpy(pi_name, lifr->lifr_name, sizeof (pi_name)); 4247c478bd9Sstevel@tonic-gate if ((cp = strchr(pi_name, IF_SEPARATOR)) != NULL) 4257c478bd9Sstevel@tonic-gate *cp = '\0'; 4267c478bd9Sstevel@tonic-gate 427e11c3f44Smeem if (pii_process(af, pi_name, &pii)) { 4287c478bd9Sstevel@tonic-gate /* The phyint is fine. So process the logint */ 4297c478bd9Sstevel@tonic-gate logint_init_from_k(pii, lifr->lifr_name); 43006cdd167Smeem check_addr_unique(pii, &lifr->lifr_addr); 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate free(buf); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* 436e11c3f44Smeem * Scan for groups, phyints and logints that have disappeared from the 4377c478bd9Sstevel@tonic-gate * kernel, and delete them. 4387c478bd9Sstevel@tonic-gate */ 439e6ed03fcSmeem for (pii = phyint_instances; pii != NULL; pii = next_pii) { 4407c478bd9Sstevel@tonic-gate next_pii = pii->pii_next; 4417c478bd9Sstevel@tonic-gate check_if_removed(pii); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate 444e11c3f44Smeem for (pg = phyint_groups; pg != NULL; pg = next_pg) { 445e11c3f44Smeem next_pg = pg->pg_next; 446e11c3f44Smeem if (!pg->pg_in_use) { 447e11c3f44Smeem phyint_group_delete(pg); 448e11c3f44Smeem continue; 449e11c3f44Smeem } 450e11c3f44Smeem /* 451e11c3f44Smeem * Refresh the group's state. This is necessary since the 452e11c3f44Smeem * group's state is defined by the set of usable interfaces in 453e11c3f44Smeem * the group, and an interface is considered unusable if all 454e11c3f44Smeem * of its addresses are down. When an address goes down/up, 455e11c3f44Smeem * the RTM_DELADDR/RTM_NEWADDR brings us through here. 456e11c3f44Smeem */ 457e11c3f44Smeem phyint_group_refresh_state(pg); 458e11c3f44Smeem } 459e11c3f44Smeem 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * Select a test address for sending probes on each phyint instance 4627c478bd9Sstevel@tonic-gate */ 4637c478bd9Sstevel@tonic-gate select_test_ifs(); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* 466e11c3f44Smeem * Handle link up/down notifications. 4677c478bd9Sstevel@tonic-gate */ 4687c478bd9Sstevel@tonic-gate process_link_state_changes(); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* 47206cdd167Smeem * Check that a given test address is unique across all of the interfaces in a 47306cdd167Smeem * group. (e.g., IPv6 link-locals may not be inherently unique, and binding 47406cdd167Smeem * to such an (IFF_NOFAILOVER) address can produce unexpected results.) 475e6ed03fcSmeem * Any issues will be reported by check_testconfig(). 4767c478bd9Sstevel@tonic-gate */ 4777c478bd9Sstevel@tonic-gate static void 47806cdd167Smeem check_addr_unique(struct phyint_instance *ourpii, struct sockaddr_storage *ss) 4797c478bd9Sstevel@tonic-gate { 4807c478bd9Sstevel@tonic-gate struct phyint *pi; 48106cdd167Smeem struct phyint_group *pg; 4827c478bd9Sstevel@tonic-gate struct in6_addr addr; 4837c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 4847c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 4857c478bd9Sstevel@tonic-gate 48606cdd167Smeem if (ss->ss_family == AF_INET) { 48706cdd167Smeem sin = (struct sockaddr_in *)ss; 4887c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &addr); 4897c478bd9Sstevel@tonic-gate } else { 49006cdd167Smeem assert(ss->ss_family == AF_INET6); 49106cdd167Smeem addr = ((struct sockaddr_in6 *)ss)->sin6_addr; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* 49506cdd167Smeem * For anonymous groups, every interface is assumed to be on its own 49606cdd167Smeem * link, so there is no chance of overlapping addresses. 4977c478bd9Sstevel@tonic-gate */ 49806cdd167Smeem pg = ourpii->pii_phyint->pi_group; 49906cdd167Smeem if (pg == phyint_anongroup) 50006cdd167Smeem return; 50106cdd167Smeem 50206cdd167Smeem /* 50306cdd167Smeem * Walk the list of phyint instances in the group and check for test 50406cdd167Smeem * addresses matching ours. Of course, we skip ourself. 50506cdd167Smeem */ 50606cdd167Smeem for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext) { 50706cdd167Smeem pii = PHYINT_INSTANCE(pi, ss->ss_family); 50806cdd167Smeem if (pii == NULL || pii == ourpii || 50906cdd167Smeem pii->pii_probe_logint == NULL) 5107c478bd9Sstevel@tonic-gate continue; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate /* 513e6ed03fcSmeem * If this test address is not unique, set the dupaddr bit. 5147c478bd9Sstevel@tonic-gate */ 515e6ed03fcSmeem if (IN6_ARE_ADDR_EQUAL(&addr, &pii->pii_probe_logint->li_addr)) 5167c478bd9Sstevel@tonic-gate pii->pii_probe_logint->li_dupaddr = 1; 5177c478bd9Sstevel@tonic-gate } 51806cdd167Smeem } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate /* 5217c478bd9Sstevel@tonic-gate * Stop probing an interface. Called when an interface is offlined. 5227c478bd9Sstevel@tonic-gate * The probe socket is closed on each interface instance, and the 5237c478bd9Sstevel@tonic-gate * interface state set to PI_OFFLINE. 5247c478bd9Sstevel@tonic-gate */ 525e11c3f44Smeem void 5267c478bd9Sstevel@tonic-gate stop_probing(struct phyint *pi) 5277c478bd9Sstevel@tonic-gate { 5287c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate pii = pi->pi_v4; 5317c478bd9Sstevel@tonic-gate if (pii != NULL) { 5327c478bd9Sstevel@tonic-gate if (pii->pii_probe_sock != -1) 5337c478bd9Sstevel@tonic-gate close_probe_socket(pii, _B_TRUE); 5347c478bd9Sstevel@tonic-gate pii->pii_probe_logint = NULL; 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate pii = pi->pi_v6; 5387c478bd9Sstevel@tonic-gate if (pii != NULL) { 5397c478bd9Sstevel@tonic-gate if (pii->pii_probe_sock != -1) 5407c478bd9Sstevel@tonic-gate close_probe_socket(pii, _B_TRUE); 5417c478bd9Sstevel@tonic-gate pii->pii_probe_logint = NULL; 5427c478bd9Sstevel@tonic-gate } 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate phyint_chstate(pi, PI_OFFLINE); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 547921e7e07Smeem enum { BAD_TESTFLAGS, OK_TESTFLAGS, BEST_TESTFLAGS }; 548921e7e07Smeem 5497c478bd9Sstevel@tonic-gate /* 550921e7e07Smeem * Rate the provided test flags. By definition, IFF_NOFAILOVER must be set. 551921e7e07Smeem * IFF_UP must also be set so that the associated address can be used as a 552921e7e07Smeem * source address. Further, we must be able to exchange packets with local 553921e7e07Smeem * destinations, so IFF_NOXMIT and IFF_NOLOCAL must be clear. For historical 554921e7e07Smeem * reasons, we have a proclivity for IFF_DEPRECATED IPv4 test addresses. 555921e7e07Smeem */ 556921e7e07Smeem static int 557921e7e07Smeem rate_testflags(uint64_t flags) 558921e7e07Smeem { 559921e7e07Smeem if ((flags & (IFF_NOFAILOVER | IFF_UP)) != (IFF_NOFAILOVER | IFF_UP)) 560921e7e07Smeem return (BAD_TESTFLAGS); 561921e7e07Smeem 562921e7e07Smeem if ((flags & (IFF_NOXMIT | IFF_NOLOCAL)) != 0) 563921e7e07Smeem return (BAD_TESTFLAGS); 564921e7e07Smeem 565921e7e07Smeem if ((flags & (IFF_IPV6 | IFF_DEPRECATED)) == IFF_DEPRECATED) 566921e7e07Smeem return (BEST_TESTFLAGS); 567921e7e07Smeem 568921e7e07Smeem if ((flags & (IFF_IPV6 | IFF_DEPRECATED)) == IFF_IPV6) 569921e7e07Smeem return (BEST_TESTFLAGS); 570921e7e07Smeem 571921e7e07Smeem return (OK_TESTFLAGS); 572921e7e07Smeem } 573921e7e07Smeem 574921e7e07Smeem /* 575921e7e07Smeem * Attempt to select a test address for each phyint instance. 576921e7e07Smeem * Call phyint_inst_sockinit() to complete the initializations. 5777c478bd9Sstevel@tonic-gate */ 5787c478bd9Sstevel@tonic-gate static void 5797c478bd9Sstevel@tonic-gate select_test_ifs(void) 5807c478bd9Sstevel@tonic-gate { 5817c478bd9Sstevel@tonic-gate struct phyint *pi; 5827c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 5837c478bd9Sstevel@tonic-gate struct phyint_instance *next_pii; 5847c478bd9Sstevel@tonic-gate struct logint *li; 585921e7e07Smeem struct logint *probe_logint; 5867c478bd9Sstevel@tonic-gate boolean_t target_scan_reqd = _B_FALSE; 587921e7e07Smeem int rating; 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) 5907c478bd9Sstevel@tonic-gate logdebug("select_test_ifs\n"); 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate /* 5937c478bd9Sstevel@tonic-gate * For each phyint instance, do the test address selection 5947c478bd9Sstevel@tonic-gate */ 5957c478bd9Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = next_pii) { 5967c478bd9Sstevel@tonic-gate next_pii = pii->pii_next; 597921e7e07Smeem probe_logint = NULL; 598921e7e07Smeem 5997c478bd9Sstevel@tonic-gate /* 600e11c3f44Smeem * An interface that is offline should not be probed. 601e11c3f44Smeem * IFF_OFFLINE interfaces should always be PI_OFFLINE 6027c478bd9Sstevel@tonic-gate * unless some other entity has set the offline flag. 6037c478bd9Sstevel@tonic-gate */ 6047c478bd9Sstevel@tonic-gate if (pii->pii_phyint->pi_flags & IFF_OFFLINE) { 6057c478bd9Sstevel@tonic-gate if (pii->pii_phyint->pi_state != PI_OFFLINE) { 6067c478bd9Sstevel@tonic-gate logerr("shouldn't be probing offline" 6077c478bd9Sstevel@tonic-gate " interface %s (state is: %u)." 6087c478bd9Sstevel@tonic-gate " Stopping probes.\n", 6097c478bd9Sstevel@tonic-gate pii->pii_phyint->pi_name, 6107c478bd9Sstevel@tonic-gate pii->pii_phyint->pi_state); 6117c478bd9Sstevel@tonic-gate stop_probing(pii->pii_phyint); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate continue; 614e11c3f44Smeem } else { 615e11c3f44Smeem /* 616e11c3f44Smeem * If something cleared IFF_OFFLINE (e.g., by accident 617e11c3f44Smeem * because the SIOCGLIFFLAGS/SIOCSLIFFLAGS sequence is 618e11c3f44Smeem * inherently racy), the phyint may still be offline. 619e11c3f44Smeem * Just ignore it. 620e11c3f44Smeem */ 621e11c3f44Smeem if (pii->pii_phyint->pi_state == PI_OFFLINE) 622e11c3f44Smeem continue; 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate 625921e7e07Smeem li = pii->pii_probe_logint; 626921e7e07Smeem if (li != NULL) { 6277c478bd9Sstevel@tonic-gate /* 628921e7e07Smeem * We've already got a test address; only proceed 629921e7e07Smeem * if it's suboptimal. 6307c478bd9Sstevel@tonic-gate */ 631921e7e07Smeem if (rate_testflags(li->li_flags) == BEST_TESTFLAGS) 632921e7e07Smeem continue; 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate /* 6367c478bd9Sstevel@tonic-gate * Walk the logints of this phyint instance, and select 6377c478bd9Sstevel@tonic-gate * the best available test address 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate for (li = pii->pii_logint; li != NULL; li = li->li_next) { 6407c478bd9Sstevel@tonic-gate /* 64106cdd167Smeem * Skip 0.0.0.0 addresses, as those are never 64206cdd167Smeem * actually usable. 64306cdd167Smeem */ 64406cdd167Smeem if (pii->pii_af == AF_INET && 64506cdd167Smeem IN6_IS_ADDR_V4MAPPED_ANY(&li->li_addr)) 64606cdd167Smeem continue; 64706cdd167Smeem 64806cdd167Smeem /* 6497c478bd9Sstevel@tonic-gate * Skip any IPv6 logints that are not link-local, 6507c478bd9Sstevel@tonic-gate * since we should always have a link-local address 6517c478bd9Sstevel@tonic-gate * anyway and in6_data() expects link-local replies. 6527c478bd9Sstevel@tonic-gate */ 6537c478bd9Sstevel@tonic-gate if (pii->pii_af == AF_INET6 && 6547c478bd9Sstevel@tonic-gate !IN6_IS_ADDR_LINKLOCAL(&li->li_addr)) 6557c478bd9Sstevel@tonic-gate continue; 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* 658921e7e07Smeem * Rate the testflags. If we've found an optimal 659921e7e07Smeem * match, then break out; otherwise, record the most 660921e7e07Smeem * recent OK one. 6617c478bd9Sstevel@tonic-gate */ 662921e7e07Smeem rating = rate_testflags(li->li_flags); 663921e7e07Smeem if (rating == BAD_TESTFLAGS) 664921e7e07Smeem continue; 665921e7e07Smeem 666921e7e07Smeem probe_logint = li; 667921e7e07Smeem if (rating == BEST_TESTFLAGS) 6687c478bd9Sstevel@tonic-gate break; 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* 672921e7e07Smeem * If the probe logint has changed, ditch the old one. 6737c478bd9Sstevel@tonic-gate */ 674921e7e07Smeem if (pii->pii_probe_logint != NULL && 675921e7e07Smeem pii->pii_probe_logint != probe_logint) { 6767c478bd9Sstevel@tonic-gate if (pii->pii_probe_sock != -1) 6777c478bd9Sstevel@tonic-gate close_probe_socket(pii, _B_TRUE); 6787c478bd9Sstevel@tonic-gate pii->pii_probe_logint = NULL; 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 681921e7e07Smeem if (probe_logint == NULL) { 6827c478bd9Sstevel@tonic-gate /* 683e6ed03fcSmeem * We don't have a test address; zero out the probe 684e6ed03fcSmeem * stats array since it is no longer relevant. 685e6ed03fcSmeem * Optimize by checking if it is already zeroed out. 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate int pr_ndx; 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate pr_ndx = PROBE_INDEX_PREV(pii->pii_probe_next); 6907c478bd9Sstevel@tonic-gate if (pii->pii_probes[pr_ndx].pr_status != PR_UNUSED) { 6917c478bd9Sstevel@tonic-gate clear_pii_probe_stats(pii); 6927c478bd9Sstevel@tonic-gate reset_crtt_all(pii->pii_phyint); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate continue; 695921e7e07Smeem } else if (probe_logint == pii->pii_probe_logint) { 6967c478bd9Sstevel@tonic-gate /* 6977c478bd9Sstevel@tonic-gate * If we didn't find any new test addr, go to the 6987c478bd9Sstevel@tonic-gate * next phyint. 6997c478bd9Sstevel@tonic-gate */ 7007c478bd9Sstevel@tonic-gate continue; 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate /* 7047c478bd9Sstevel@tonic-gate * The phyint is either being assigned a new testaddr 7057c478bd9Sstevel@tonic-gate * or is being assigned a testaddr for the 1st time. 7067c478bd9Sstevel@tonic-gate * Need to initialize the phyint socket 7077c478bd9Sstevel@tonic-gate */ 708921e7e07Smeem pii->pii_probe_logint = probe_logint; 7097c478bd9Sstevel@tonic-gate if (!phyint_inst_sockinit(pii)) { 7107c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) { 7117c478bd9Sstevel@tonic-gate logdebug("select_test_ifs: " 7127c478bd9Sstevel@tonic-gate "phyint_sockinit failed\n"); 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate phyint_inst_delete(pii); 7157c478bd9Sstevel@tonic-gate continue; 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate /* 7197c478bd9Sstevel@tonic-gate * This phyint instance is now enabled for probes; this 7207c478bd9Sstevel@tonic-gate * impacts our state machine in two ways: 7217c478bd9Sstevel@tonic-gate * 7227c478bd9Sstevel@tonic-gate * 1. If we're probe *capable* as well (i.e., we have 7237c478bd9Sstevel@tonic-gate * probe targets) and the interface is in PI_NOTARGETS, 7247c478bd9Sstevel@tonic-gate * then transition to PI_RUNNING. 7257c478bd9Sstevel@tonic-gate * 7267c478bd9Sstevel@tonic-gate * 2. If we're not probe capable, and the other phyint 7277c478bd9Sstevel@tonic-gate * instance is also not probe capable, and we were in 7287c478bd9Sstevel@tonic-gate * PI_RUNNING, then transition to PI_NOTARGETS. 7297c478bd9Sstevel@tonic-gate * 7307c478bd9Sstevel@tonic-gate * Also see the state diagram in mpd_probe.c. 7317c478bd9Sstevel@tonic-gate */ 7327c478bd9Sstevel@tonic-gate if (PROBE_CAPABLE(pii)) { 7337c478bd9Sstevel@tonic-gate if (pii->pii_phyint->pi_state == PI_NOTARGETS) 7347c478bd9Sstevel@tonic-gate phyint_chstate(pii->pii_phyint, PI_RUNNING); 7357c478bd9Sstevel@tonic-gate } else if (!PROBE_CAPABLE(phyint_inst_other(pii))) { 7367c478bd9Sstevel@tonic-gate if (pii->pii_phyint->pi_state == PI_RUNNING) 7377c478bd9Sstevel@tonic-gate phyint_chstate(pii->pii_phyint, PI_NOTARGETS); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate /* 7417c478bd9Sstevel@tonic-gate * If no targets are currently known for this phyint 7427c478bd9Sstevel@tonic-gate * we need to call init_router_targets. Since 7437c478bd9Sstevel@tonic-gate * init_router_targets() initializes the list of targets 7447c478bd9Sstevel@tonic-gate * for all phyints it is done below the loop. 7457c478bd9Sstevel@tonic-gate */ 7467c478bd9Sstevel@tonic-gate if (pii->pii_targets == NULL) 7477c478bd9Sstevel@tonic-gate target_scan_reqd = _B_TRUE; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate /* 7507c478bd9Sstevel@tonic-gate * Start the probe timer for this instance. 7517c478bd9Sstevel@tonic-gate */ 75206cdd167Smeem if (!pii->pii_basetime_inited && PROBE_ENABLED(pii)) { 7537c478bd9Sstevel@tonic-gate start_timer(pii); 7547c478bd9Sstevel@tonic-gate pii->pii_basetime_inited = 1; 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate /* 759e11c3f44Smeem * Scan the interface list for any interfaces that are PI_FAILED or 760e11c3f44Smeem * PI_NOTARGETS but no longer enabled to send probes, and call 761e11c3f44Smeem * phyint_check_for_repair() to see if the link state indicates that 762e11c3f44Smeem * the interface should be repaired. Also see the state diagram in 7637c478bd9Sstevel@tonic-gate * mpd_probe.c. 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 766e11c3f44Smeem if ((!PROBE_ENABLED(pi->pi_v4) && !PROBE_ENABLED(pi->pi_v6)) && 767e11c3f44Smeem (pi->pi_state == PI_FAILED || 768e11c3f44Smeem pi->pi_state == PI_NOTARGETS)) { 7697c478bd9Sstevel@tonic-gate phyint_check_for_repair(pi); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 773e6ed03fcSmeem check_testconfig(); 774e6ed03fcSmeem 7757c478bd9Sstevel@tonic-gate /* 7767c478bd9Sstevel@tonic-gate * Try to populate the target list. init_router_targets populates 7777c478bd9Sstevel@tonic-gate * the target list from the routing table. If our target list is 7787c478bd9Sstevel@tonic-gate * still empty, init_host_targets adds host targets based on the 7797c478bd9Sstevel@tonic-gate * host target list of other phyints in the group. 7807c478bd9Sstevel@tonic-gate */ 7817c478bd9Sstevel@tonic-gate if (target_scan_reqd) { 7827c478bd9Sstevel@tonic-gate init_router_targets(); 7837c478bd9Sstevel@tonic-gate init_host_targets(); 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate /* 788e3e7cd29Smeem * Check test address configuration, and log notices/errors if appropriate. 789e3e7cd29Smeem * Note that this function only logs pre-existing conditions (e.g., that 790e3e7cd29Smeem * probe-based failure detection is disabled). 791e6ed03fcSmeem */ 792e6ed03fcSmeem static void 793e6ed03fcSmeem check_testconfig(void) 794e6ed03fcSmeem { 795e6ed03fcSmeem struct phyint *pi; 796e6ed03fcSmeem struct logint *li; 797e6ed03fcSmeem char abuf[INET6_ADDRSTRLEN]; 798e3e7cd29Smeem int pri; 799e6ed03fcSmeem 800e6ed03fcSmeem for (pi = phyints; pi != NULL; pi = pi->pi_next) { 801e6ed03fcSmeem if (pi->pi_flags & IFF_OFFLINE) 802e6ed03fcSmeem continue; 803e6ed03fcSmeem 804e6ed03fcSmeem if (PROBE_ENABLED(pi->pi_v4) || PROBE_ENABLED(pi->pi_v6)) { 805e6ed03fcSmeem if (pi->pi_taddrmsg_printed || 806e6ed03fcSmeem pi->pi_duptaddrmsg_printed) { 807e3e7cd29Smeem if (pi->pi_duptaddrmsg_printed) 808e3e7cd29Smeem pri = LOG_ERR; 809e3e7cd29Smeem else 810e3e7cd29Smeem pri = LOG_INFO; 811e3e7cd29Smeem logmsg(pri, "Test address now configured on " 812e6ed03fcSmeem "interface %s; enabling probe-based " 813e6ed03fcSmeem "failure detection on it\n", pi->pi_name); 814e6ed03fcSmeem pi->pi_taddrmsg_printed = 0; 815e6ed03fcSmeem pi->pi_duptaddrmsg_printed = 0; 816e6ed03fcSmeem } 817e6ed03fcSmeem continue; 818e6ed03fcSmeem } 819e6ed03fcSmeem 820e6ed03fcSmeem li = NULL; 821e6ed03fcSmeem if (pi->pi_v4 != NULL && pi->pi_v4->pii_probe_logint != NULL && 822e6ed03fcSmeem pi->pi_v4->pii_probe_logint->li_dupaddr) 823e6ed03fcSmeem li = pi->pi_v4->pii_probe_logint; 824e6ed03fcSmeem 825e6ed03fcSmeem if (pi->pi_v6 != NULL && pi->pi_v6->pii_probe_logint != NULL && 826e6ed03fcSmeem pi->pi_v6->pii_probe_logint->li_dupaddr) 827e6ed03fcSmeem li = pi->pi_v6->pii_probe_logint; 828e6ed03fcSmeem 829e11c3f44Smeem if (li != NULL && li->li_dupaddr) { 830e11c3f44Smeem if (pi->pi_duptaddrmsg_printed) 831e11c3f44Smeem continue; 832e11c3f44Smeem logerr("Test address %s is not unique in group; " 833e11c3f44Smeem "disabling probe-based failure detection on %s\n", 834e11c3f44Smeem pr_addr(li->li_phyint_inst->pii_af, 835e11c3f44Smeem li->li_addr, abuf, sizeof (abuf)), pi->pi_name); 836e6ed03fcSmeem pi->pi_duptaddrmsg_printed = 1; 837e6ed03fcSmeem continue; 838e6ed03fcSmeem } 839e6ed03fcSmeem 840e6ed03fcSmeem if (getcurrentsec() < pi->pi_taddrthresh) 841e6ed03fcSmeem continue; 842e6ed03fcSmeem 843e6ed03fcSmeem if (!pi->pi_taddrmsg_printed) { 844e3e7cd29Smeem logtrace("No test address configured on interface %s; " 845e6ed03fcSmeem "disabling probe-based failure detection on it\n", 846e6ed03fcSmeem pi->pi_name); 847e6ed03fcSmeem pi->pi_taddrmsg_printed = 1; 848e6ed03fcSmeem } 849e6ed03fcSmeem } 850e6ed03fcSmeem } 851e6ed03fcSmeem 852e6ed03fcSmeem /* 8537c478bd9Sstevel@tonic-gate * Check phyint group configuration, to detect any inconsistencies, 8547c478bd9Sstevel@tonic-gate * and log an error message. This is called from runtimeouts every 8557c478bd9Sstevel@tonic-gate * 20 secs. But the error message is displayed once. If the 8567c478bd9Sstevel@tonic-gate * consistency is resolved by the admin, a recovery message is displayed 8577c478bd9Sstevel@tonic-gate * once. 8587c478bd9Sstevel@tonic-gate */ 8597c478bd9Sstevel@tonic-gate static void 8607c478bd9Sstevel@tonic-gate check_config(void) 8617c478bd9Sstevel@tonic-gate { 8627c478bd9Sstevel@tonic-gate struct phyint_group *pg; 8637c478bd9Sstevel@tonic-gate struct phyint *pi; 8647c478bd9Sstevel@tonic-gate boolean_t v4_in_group; 8657c478bd9Sstevel@tonic-gate boolean_t v6_in_group; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate /* 868e11c3f44Smeem * All phyints of a group must be homogeneous to ensure that they can 869e11c3f44Smeem * take over for one another. If any phyint in a group has IPv4 870e11c3f44Smeem * plumbed, check that all phyints have IPv4 plumbed. Do a similar 871e11c3f44Smeem * check for IPv6. 8727c478bd9Sstevel@tonic-gate */ 8737c478bd9Sstevel@tonic-gate for (pg = phyint_groups; pg != NULL; pg = pg->pg_next) { 8747c478bd9Sstevel@tonic-gate if (pg == phyint_anongroup) 8757c478bd9Sstevel@tonic-gate continue; 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate v4_in_group = _B_FALSE; 8787c478bd9Sstevel@tonic-gate v6_in_group = _B_FALSE; 8797c478bd9Sstevel@tonic-gate /* 8807c478bd9Sstevel@tonic-gate * 1st pass. Determine if at least 1 phyint in the group 8817c478bd9Sstevel@tonic-gate * has IPv4 plumbed and if so set v4_in_group to true. 8827c478bd9Sstevel@tonic-gate * Repeat similarly for IPv6. 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext) { 8857c478bd9Sstevel@tonic-gate if (pi->pi_v4 != NULL) 8867c478bd9Sstevel@tonic-gate v4_in_group = _B_TRUE; 8877c478bd9Sstevel@tonic-gate if (pi->pi_v6 != NULL) 8887c478bd9Sstevel@tonic-gate v6_in_group = _B_TRUE; 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate /* 8927c478bd9Sstevel@tonic-gate * 2nd pass. If v4_in_group is true, check that phyint 8937c478bd9Sstevel@tonic-gate * has IPv4 plumbed. Repeat similarly for IPv6. Print 8947c478bd9Sstevel@tonic-gate * out a message the 1st time only. 8957c478bd9Sstevel@tonic-gate */ 8967c478bd9Sstevel@tonic-gate for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext) { 8977c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_OFFLINE) 8987c478bd9Sstevel@tonic-gate continue; 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate if (v4_in_group == _B_TRUE && pi->pi_v4 == NULL) { 9017c478bd9Sstevel@tonic-gate if (!pi->pi_cfgmsg_printed) { 902e11c3f44Smeem logerr("IP interface %s in group %s is" 903e11c3f44Smeem " not plumbed for IPv4, affecting" 904e11c3f44Smeem " IPv4 connectivity\n", 9057c478bd9Sstevel@tonic-gate pi->pi_name, 9067c478bd9Sstevel@tonic-gate pi->pi_group->pg_name); 9077c478bd9Sstevel@tonic-gate pi->pi_cfgmsg_printed = 1; 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate } else if (v6_in_group == _B_TRUE && 9107c478bd9Sstevel@tonic-gate pi->pi_v6 == NULL) { 9117c478bd9Sstevel@tonic-gate if (!pi->pi_cfgmsg_printed) { 912e11c3f44Smeem logerr("IP interface %s in group %s is" 913e11c3f44Smeem " not plumbed for IPv6, affecting" 914e11c3f44Smeem " IPv6 connectivity\n", 9157c478bd9Sstevel@tonic-gate pi->pi_name, 9167c478bd9Sstevel@tonic-gate pi->pi_group->pg_name); 9177c478bd9Sstevel@tonic-gate pi->pi_cfgmsg_printed = 1; 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate } else { 9207c478bd9Sstevel@tonic-gate /* 9217c478bd9Sstevel@tonic-gate * The phyint matches the group configuration, 9227c478bd9Sstevel@tonic-gate * if we have reached this point. If it was 9237c478bd9Sstevel@tonic-gate * improperly configured earlier, log an 9247c478bd9Sstevel@tonic-gate * error recovery message 9257c478bd9Sstevel@tonic-gate */ 9267c478bd9Sstevel@tonic-gate if (pi->pi_cfgmsg_printed) { 927e11c3f44Smeem logerr("IP interface %s is now" 928e11c3f44Smeem " consistent with group %s " 929e11c3f44Smeem " and connectivity is restored\n", 930e11c3f44Smeem pi->pi_name, pi->pi_group->pg_name); 9317c478bd9Sstevel@tonic-gate pi->pi_cfgmsg_printed = 0; 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate } 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate } 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate /* 9407c478bd9Sstevel@tonic-gate * Timer mechanism using relative time (in milliseconds) from the 9417c478bd9Sstevel@tonic-gate * previous timer event. Timers exceeding TIMER_INFINITY milliseconds 9427c478bd9Sstevel@tonic-gate * will fire after TIMER_INFINITY milliseconds. 9437c478bd9Sstevel@tonic-gate * Unsigned arithmetic note: We assume a 32-bit circular sequence space for 9447c478bd9Sstevel@tonic-gate * time values. Hence 2 consecutive timer events cannot be spaced farther 9457c478bd9Sstevel@tonic-gate * than 0x7fffffff. We call this TIMER_INFINITY, and it is the maximum value 9467c478bd9Sstevel@tonic-gate * that can be passed for the delay parameter of timer_schedule() 9477c478bd9Sstevel@tonic-gate */ 9487c478bd9Sstevel@tonic-gate static uint_t timer_next; /* Currently scheduled timeout */ 9497c478bd9Sstevel@tonic-gate static boolean_t timer_active = _B_FALSE; /* SIGALRM has not yet occurred */ 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate static void 9527c478bd9Sstevel@tonic-gate timer_init(void) 9537c478bd9Sstevel@tonic-gate { 9547c478bd9Sstevel@tonic-gate timer_next = getcurrenttime() + TIMER_INFINITY; 9557c478bd9Sstevel@tonic-gate /* 9567c478bd9Sstevel@tonic-gate * The call to run_timeouts() will get the timer started 9577c478bd9Sstevel@tonic-gate * Since there are no phyints at this point, the timer will 9587c478bd9Sstevel@tonic-gate * be set for IF_SCAN_INTERVAL ms. 9597c478bd9Sstevel@tonic-gate */ 9607c478bd9Sstevel@tonic-gate run_timeouts(); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate /* 9647c478bd9Sstevel@tonic-gate * Make sure the next SIGALRM occurs delay milliseconds from the current 9657c478bd9Sstevel@tonic-gate * time if not earlier. We are interested only in time differences. 9667c478bd9Sstevel@tonic-gate */ 9677c478bd9Sstevel@tonic-gate void 9687c478bd9Sstevel@tonic-gate timer_schedule(uint_t delay) 9697c478bd9Sstevel@tonic-gate { 9707c478bd9Sstevel@tonic-gate uint_t now; 9717c478bd9Sstevel@tonic-gate struct itimerval itimerval; 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 9747c478bd9Sstevel@tonic-gate logdebug("timer_schedule(%u)\n", delay); 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate assert(delay <= TIMER_INFINITY); 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate now = getcurrenttime(); 9797c478bd9Sstevel@tonic-gate if (delay == 0) { 9807c478bd9Sstevel@tonic-gate /* Minimum allowed delay */ 9817c478bd9Sstevel@tonic-gate delay = 1; 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate /* Will this timer occur before the currently scheduled SIGALRM? */ 9847c478bd9Sstevel@tonic-gate if (timer_active && TIME_GE(now + delay, timer_next)) { 9857c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 9867c478bd9Sstevel@tonic-gate logdebug("timer_schedule(%u) - no action: " 9877c478bd9Sstevel@tonic-gate "now %u next %u\n", delay, now, timer_next); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate return; 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate timer_next = now + delay; 9927c478bd9Sstevel@tonic-gate 9937c478bd9Sstevel@tonic-gate itimerval.it_value.tv_sec = delay / 1000; 9947c478bd9Sstevel@tonic-gate itimerval.it_value.tv_usec = (delay % 1000) * 1000; 9957c478bd9Sstevel@tonic-gate itimerval.it_interval.tv_sec = 0; 9967c478bd9Sstevel@tonic-gate itimerval.it_interval.tv_usec = 0; 9977c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 9987c478bd9Sstevel@tonic-gate logdebug("timer_schedule(%u): sec %ld usec %ld\n", 9997c478bd9Sstevel@tonic-gate delay, itimerval.it_value.tv_sec, 10007c478bd9Sstevel@tonic-gate itimerval.it_value.tv_usec); 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate timer_active = _B_TRUE; 10037c478bd9Sstevel@tonic-gate if (setitimer(ITIMER_REAL, &itimerval, NULL) < 0) { 10047c478bd9Sstevel@tonic-gate logperror("timer_schedule: setitimer"); 10057c478bd9Sstevel@tonic-gate exit(2); 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate 1009c61f3fa8Smeem static void 1010c61f3fa8Smeem timer_cancel(void) 1011c61f3fa8Smeem { 1012c61f3fa8Smeem struct itimerval itimerval; 1013c61f3fa8Smeem 1014c61f3fa8Smeem if (debug & D_TIMER) 1015c61f3fa8Smeem logdebug("timer_cancel()\n"); 1016c61f3fa8Smeem 1017c61f3fa8Smeem bzero(&itimerval, sizeof (itimerval)); 1018c61f3fa8Smeem if (setitimer(ITIMER_REAL, &itimerval, NULL) < 0) 1019c61f3fa8Smeem logperror("timer_cancel: setitimer"); 1020c61f3fa8Smeem } 1021c61f3fa8Smeem 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * Timer has fired. Determine when the next timer event will occur by asking 10247c478bd9Sstevel@tonic-gate * all the timer routines. Should not be called from a timer routine. 10257c478bd9Sstevel@tonic-gate */ 10267c478bd9Sstevel@tonic-gate static void 10277c478bd9Sstevel@tonic-gate run_timeouts(void) 10287c478bd9Sstevel@tonic-gate { 10297c478bd9Sstevel@tonic-gate uint_t next; 10307c478bd9Sstevel@tonic-gate uint_t next_event_time; 10317c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 10327c478bd9Sstevel@tonic-gate struct phyint_instance *next_pii; 10337c478bd9Sstevel@tonic-gate static boolean_t timeout_running; 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate /* assert that recursive timeouts don't happen. */ 10367c478bd9Sstevel@tonic-gate assert(!timeout_running); 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate timeout_running = _B_TRUE; 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 10417c478bd9Sstevel@tonic-gate logdebug("run_timeouts()\n"); 10427c478bd9Sstevel@tonic-gate 1043e6ed03fcSmeem if ((getcurrenttime() - last_initifs_time) > IF_SCAN_INTERVAL) { 1044e6ed03fcSmeem initifs(); 1045e6ed03fcSmeem check_config(); 1046e6ed03fcSmeem } 1047e6ed03fcSmeem 10487c478bd9Sstevel@tonic-gate next = TIMER_INFINITY; 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = next_pii) { 10517c478bd9Sstevel@tonic-gate next_pii = pii->pii_next; 10527c478bd9Sstevel@tonic-gate next_event_time = phyint_inst_timer(pii); 10537c478bd9Sstevel@tonic-gate if (next_event_time != TIMER_INFINITY && next_event_time < next) 10547c478bd9Sstevel@tonic-gate next = next_event_time; 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 10577c478bd9Sstevel@tonic-gate logdebug("run_timeouts(%s %s): next scheduled for" 10587c478bd9Sstevel@tonic-gate " this phyint inst %u, next scheduled global" 10597c478bd9Sstevel@tonic-gate " %u ms\n", 10607c478bd9Sstevel@tonic-gate AF_STR(pii->pii_af), pii->pii_phyint->pi_name, 10617c478bd9Sstevel@tonic-gate next_event_time, next); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate /* 10667c478bd9Sstevel@tonic-gate * Make sure initifs() is called at least once every 10677c478bd9Sstevel@tonic-gate * IF_SCAN_INTERVAL, to make sure that we are in sync 10687c478bd9Sstevel@tonic-gate * with the kernel, in case we have missed any routing 10697c478bd9Sstevel@tonic-gate * socket messages. 10707c478bd9Sstevel@tonic-gate */ 10717c478bd9Sstevel@tonic-gate if (next > IF_SCAN_INTERVAL) 10727c478bd9Sstevel@tonic-gate next = IF_SCAN_INTERVAL; 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 10757c478bd9Sstevel@tonic-gate logdebug("run_timeouts: %u ms\n", next); 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate timer_schedule(next); 10787c478bd9Sstevel@tonic-gate timeout_running = _B_FALSE; 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate static int eventpipe_read = -1; /* Used for synchronous signal delivery */ 10827c478bd9Sstevel@tonic-gate static int eventpipe_write = -1; 1083e11c3f44Smeem boolean_t cleanup_started = _B_FALSE; /* true if we're going away */ 1084e11c3f44Smeem 10857c478bd9Sstevel@tonic-gate /* 10867c478bd9Sstevel@tonic-gate * Ensure that signals are processed synchronously with the rest of 10877c478bd9Sstevel@tonic-gate * the code by just writing a one character signal number on the pipe. 10887c478bd9Sstevel@tonic-gate * The poll loop will pick this up and process the signal event. 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate static void 10917c478bd9Sstevel@tonic-gate sig_handler(int signo) 10927c478bd9Sstevel@tonic-gate { 10937c478bd9Sstevel@tonic-gate uchar_t buf = (uchar_t)signo; 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate /* 10967c478bd9Sstevel@tonic-gate * Don't write to pipe if cleanup has already begun. cleanup() 10977c478bd9Sstevel@tonic-gate * might have closed the pipe already 10987c478bd9Sstevel@tonic-gate */ 10997c478bd9Sstevel@tonic-gate if (cleanup_started) 11007c478bd9Sstevel@tonic-gate return; 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate if (eventpipe_write == -1) { 11037c478bd9Sstevel@tonic-gate logerr("sig_handler: no pipe found\n"); 11047c478bd9Sstevel@tonic-gate return; 11057c478bd9Sstevel@tonic-gate } 11067c478bd9Sstevel@tonic-gate if (write(eventpipe_write, &buf, sizeof (buf)) < 0) 11077c478bd9Sstevel@tonic-gate logperror("sig_handler: write"); 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate extern struct probes_missed probes_missed; 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate /* 11137c478bd9Sstevel@tonic-gate * Pick up a signal "byte" from the pipe and process it. 11147c478bd9Sstevel@tonic-gate */ 11157c478bd9Sstevel@tonic-gate static void 11167c478bd9Sstevel@tonic-gate in_signal(int fd) 11177c478bd9Sstevel@tonic-gate { 11187c478bd9Sstevel@tonic-gate uchar_t buf; 11197c478bd9Sstevel@tonic-gate uint64_t sent, acked, lost, unacked, unknown; 11207c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 11217c478bd9Sstevel@tonic-gate int pr_ndx; 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate switch (read(fd, &buf, sizeof (buf))) { 11247c478bd9Sstevel@tonic-gate case -1: 11257c478bd9Sstevel@tonic-gate logperror("in_signal: read"); 11267c478bd9Sstevel@tonic-gate exit(1); 11277c478bd9Sstevel@tonic-gate /* NOTREACHED */ 11287c478bd9Sstevel@tonic-gate case 1: 11297c478bd9Sstevel@tonic-gate break; 11307c478bd9Sstevel@tonic-gate case 0: 11317c478bd9Sstevel@tonic-gate logerr("in_signal: read end of file\n"); 11327c478bd9Sstevel@tonic-gate exit(1); 11337c478bd9Sstevel@tonic-gate /* NOTREACHED */ 11347c478bd9Sstevel@tonic-gate default: 11357c478bd9Sstevel@tonic-gate logerr("in_signal: read > 1\n"); 11367c478bd9Sstevel@tonic-gate exit(1); 11377c478bd9Sstevel@tonic-gate } 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate if (debug & D_TIMER) 11407c478bd9Sstevel@tonic-gate logdebug("in_signal() got %d\n", buf); 11417c478bd9Sstevel@tonic-gate 11427c478bd9Sstevel@tonic-gate switch (buf) { 11437c478bd9Sstevel@tonic-gate case SIGALRM: 11447c478bd9Sstevel@tonic-gate if (debug & D_TIMER) { 11457c478bd9Sstevel@tonic-gate uint_t now = getcurrenttime(); 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate logdebug("in_signal(SIGALRM) delta %u\n", 11487c478bd9Sstevel@tonic-gate now - timer_next); 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate timer_active = _B_FALSE; 11517c478bd9Sstevel@tonic-gate run_timeouts(); 11527c478bd9Sstevel@tonic-gate break; 11537c478bd9Sstevel@tonic-gate case SIGUSR1: 11547c478bd9Sstevel@tonic-gate logdebug("Printing configuration:\n"); 11557c478bd9Sstevel@tonic-gate /* Print out the internal tables */ 11567c478bd9Sstevel@tonic-gate phyint_inst_print_all(); 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate /* 11597c478bd9Sstevel@tonic-gate * Print out the accumulated statistics about missed 11607c478bd9Sstevel@tonic-gate * probes (happens due to scheduling delay). 11617c478bd9Sstevel@tonic-gate */ 11627c478bd9Sstevel@tonic-gate logerr("Missed sending total of %d probes spread over" 11637c478bd9Sstevel@tonic-gate " %d occurrences\n", probes_missed.pm_nprobes, 11647c478bd9Sstevel@tonic-gate probes_missed.pm_ntimes); 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate /* 11677c478bd9Sstevel@tonic-gate * Print out the accumulated statistics about probes 11687c478bd9Sstevel@tonic-gate * that were sent. 11697c478bd9Sstevel@tonic-gate */ 11707c478bd9Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; 11717c478bd9Sstevel@tonic-gate pii = pii->pii_next) { 11727c478bd9Sstevel@tonic-gate unacked = 0; 11737c478bd9Sstevel@tonic-gate acked = pii->pii_cum_stats.acked; 11747c478bd9Sstevel@tonic-gate lost = pii->pii_cum_stats.lost; 11757c478bd9Sstevel@tonic-gate sent = pii->pii_cum_stats.sent; 11767c478bd9Sstevel@tonic-gate unknown = pii->pii_cum_stats.unknown; 11777c478bd9Sstevel@tonic-gate for (pr_ndx = 0; pr_ndx < PROBE_STATS_COUNT; pr_ndx++) { 11787c478bd9Sstevel@tonic-gate switch (pii->pii_probes[pr_ndx].pr_status) { 11797c478bd9Sstevel@tonic-gate case PR_ACKED: 11807c478bd9Sstevel@tonic-gate acked++; 11817c478bd9Sstevel@tonic-gate break; 11827c478bd9Sstevel@tonic-gate case PR_LOST: 11837c478bd9Sstevel@tonic-gate lost++; 11847c478bd9Sstevel@tonic-gate break; 11857c478bd9Sstevel@tonic-gate case PR_UNACKED: 11867c478bd9Sstevel@tonic-gate unacked++; 11877c478bd9Sstevel@tonic-gate break; 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate logerr("\nProbe stats on (%s %s)\n" 11917c478bd9Sstevel@tonic-gate "Number of probes sent %lld\n" 11927c478bd9Sstevel@tonic-gate "Number of probe acks received %lld\n" 11937c478bd9Sstevel@tonic-gate "Number of probes/acks lost %lld\n" 1194e11c3f44Smeem "Number of valid unacknowledged probes %lld\n" 11957c478bd9Sstevel@tonic-gate "Number of ambiguous probe acks received %lld\n", 11967c478bd9Sstevel@tonic-gate AF_STR(pii->pii_af), pii->pii_name, 11977c478bd9Sstevel@tonic-gate sent, acked, lost, unacked, unknown); 11987c478bd9Sstevel@tonic-gate } 11997c478bd9Sstevel@tonic-gate break; 12007c478bd9Sstevel@tonic-gate case SIGHUP: 12017c478bd9Sstevel@tonic-gate logerr("SIGHUP: restart and reread config file\n"); 1202c61f3fa8Smeem /* 1203c61f3fa8Smeem * Cancel the interval timer. Needed since setitimer() uses 1204c61f3fa8Smeem * alarm() and the time left is inherited across exec(), and 1205c61f3fa8Smeem * thus the SIGALRM may be delivered before a handler has been 1206c61f3fa8Smeem * setup, causing in.mpathd to erroneously exit. 1207c61f3fa8Smeem */ 1208c61f3fa8Smeem timer_cancel(); 12097c478bd9Sstevel@tonic-gate cleanup(); 12107c478bd9Sstevel@tonic-gate (void) execv(argv0[0], argv0); 12117c478bd9Sstevel@tonic-gate _exit(0177); 12127c478bd9Sstevel@tonic-gate /* NOTREACHED */ 12137c478bd9Sstevel@tonic-gate case SIGINT: 12147c478bd9Sstevel@tonic-gate case SIGTERM: 12157c478bd9Sstevel@tonic-gate case SIGQUIT: 12167c478bd9Sstevel@tonic-gate cleanup(); 12177c478bd9Sstevel@tonic-gate exit(0); 12187c478bd9Sstevel@tonic-gate /* NOTREACHED */ 12197c478bd9Sstevel@tonic-gate default: 12207c478bd9Sstevel@tonic-gate logerr("in_signal: unknown signal: %d\n", buf); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate static void 12257c478bd9Sstevel@tonic-gate cleanup(void) 12267c478bd9Sstevel@tonic-gate { 12277c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 12287c478bd9Sstevel@tonic-gate struct phyint_instance *next_pii; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate /* 12317c478bd9Sstevel@tonic-gate * Make sure that we don't write to eventpipe in 12327c478bd9Sstevel@tonic-gate * sig_handler() if any signal notably SIGALRM, 12337c478bd9Sstevel@tonic-gate * occurs after we close the eventpipe descriptor below 12347c478bd9Sstevel@tonic-gate */ 12357c478bd9Sstevel@tonic-gate cleanup_started = _B_TRUE; 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = next_pii) { 12387c478bd9Sstevel@tonic-gate next_pii = pii->pii_next; 12397c478bd9Sstevel@tonic-gate phyint_inst_delete(pii); 12407c478bd9Sstevel@tonic-gate } 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate (void) close(ifsock_v4); 12437c478bd9Sstevel@tonic-gate (void) close(ifsock_v6); 12447c478bd9Sstevel@tonic-gate (void) close(rtsock_v4); 12457c478bd9Sstevel@tonic-gate (void) close(rtsock_v6); 12467c478bd9Sstevel@tonic-gate (void) close(lsock_v4); 12477c478bd9Sstevel@tonic-gate (void) close(lsock_v6); 12487c478bd9Sstevel@tonic-gate (void) close(0); 12497c478bd9Sstevel@tonic-gate (void) close(1); 12507c478bd9Sstevel@tonic-gate (void) close(2); 12517c478bd9Sstevel@tonic-gate (void) close(mibfd); 12527c478bd9Sstevel@tonic-gate (void) close(eventpipe_read); 12537c478bd9Sstevel@tonic-gate (void) close(eventpipe_write); 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate /* 12577c478bd9Sstevel@tonic-gate * Create pipe for signal delivery and set up signal handlers. 12587c478bd9Sstevel@tonic-gate */ 12597c478bd9Sstevel@tonic-gate static void 12607c478bd9Sstevel@tonic-gate setup_eventpipe(void) 12617c478bd9Sstevel@tonic-gate { 12627c478bd9Sstevel@tonic-gate int fds[2]; 12637c478bd9Sstevel@tonic-gate struct sigaction act; 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate if ((pipe(fds)) < 0) { 12667c478bd9Sstevel@tonic-gate logperror("setup_eventpipe: pipe"); 12677c478bd9Sstevel@tonic-gate exit(1); 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate eventpipe_read = fds[0]; 12707c478bd9Sstevel@tonic-gate eventpipe_write = fds[1]; 12717c478bd9Sstevel@tonic-gate if (poll_add(eventpipe_read) == -1) { 12727c478bd9Sstevel@tonic-gate exit(1); 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate act.sa_handler = sig_handler; 12767c478bd9Sstevel@tonic-gate act.sa_flags = SA_RESTART; 12777c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &act, NULL); 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate (void) sigset(SIGHUP, sig_handler); 12807c478bd9Sstevel@tonic-gate (void) sigset(SIGUSR1, sig_handler); 12817c478bd9Sstevel@tonic-gate (void) sigset(SIGTERM, sig_handler); 12827c478bd9Sstevel@tonic-gate (void) sigset(SIGINT, sig_handler); 12837c478bd9Sstevel@tonic-gate (void) sigset(SIGQUIT, sig_handler); 12847c478bd9Sstevel@tonic-gate } 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate /* 12877c478bd9Sstevel@tonic-gate * Create a routing socket for receiving RTM_IFINFO messages. 12887c478bd9Sstevel@tonic-gate */ 12897c478bd9Sstevel@tonic-gate static int 12907c478bd9Sstevel@tonic-gate setup_rtsock(int af) 12917c478bd9Sstevel@tonic-gate { 12927c478bd9Sstevel@tonic-gate int s; 12937c478bd9Sstevel@tonic-gate int flags; 1294e11c3f44Smeem int aware = RTAW_UNDER_IPMP; 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, af); 12977c478bd9Sstevel@tonic-gate if (s == -1) { 12987c478bd9Sstevel@tonic-gate logperror("setup_rtsock: socket PF_ROUTE"); 12997c478bd9Sstevel@tonic-gate exit(1); 13007c478bd9Sstevel@tonic-gate } 1301e11c3f44Smeem 1302e11c3f44Smeem if (setsockopt(s, SOL_ROUTE, RT_AWARE, &aware, sizeof (aware)) == -1) { 1303e11c3f44Smeem logperror("setup_rtsock: setsockopt RT_AWARE"); 1304e11c3f44Smeem (void) close(s); 1305e11c3f44Smeem exit(1); 1306e11c3f44Smeem } 1307e11c3f44Smeem 13087c478bd9Sstevel@tonic-gate if ((flags = fcntl(s, F_GETFL, 0)) < 0) { 13097c478bd9Sstevel@tonic-gate logperror("setup_rtsock: fcntl F_GETFL"); 13107c478bd9Sstevel@tonic-gate (void) close(s); 13117c478bd9Sstevel@tonic-gate exit(1); 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate if ((fcntl(s, F_SETFL, flags | O_NONBLOCK)) < 0) { 13147c478bd9Sstevel@tonic-gate logperror("setup_rtsock: fcntl F_SETFL"); 13157c478bd9Sstevel@tonic-gate (void) close(s); 13167c478bd9Sstevel@tonic-gate exit(1); 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate if (poll_add(s) == -1) { 13197c478bd9Sstevel@tonic-gate (void) close(s); 13207c478bd9Sstevel@tonic-gate exit(1); 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate return (s); 13237c478bd9Sstevel@tonic-gate } 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate * Process an RTM_IFINFO message received on a routing socket. 13277c478bd9Sstevel@tonic-gate * The return value indicates whether a full interface scan is required. 1328e11c3f44Smeem * Link up/down notifications are reflected in the IFF_RUNNING flag. 13297c478bd9Sstevel@tonic-gate * If just the state of the IFF_RUNNING interface flag has changed, a 13307c478bd9Sstevel@tonic-gate * a full interface scan isn't required. 13317c478bd9Sstevel@tonic-gate */ 13327c478bd9Sstevel@tonic-gate static boolean_t 13337c478bd9Sstevel@tonic-gate process_rtm_ifinfo(if_msghdr_t *ifm, int type) 13347c478bd9Sstevel@tonic-gate { 13357c478bd9Sstevel@tonic-gate struct sockaddr_dl *sdl; 13367c478bd9Sstevel@tonic-gate struct phyint *pi; 13377c478bd9Sstevel@tonic-gate uint64_t old_flags; 13387c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate assert(ifm->ifm_type == RTM_IFINFO && ifm->ifm_addrs == RTA_IFP); 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate /* 13437c478bd9Sstevel@tonic-gate * Although the sockaddr_dl structure is directly after the 13447c478bd9Sstevel@tonic-gate * if_msghdr_t structure. At the time of writing, the size of the 13457c478bd9Sstevel@tonic-gate * if_msghdr_t structure is different on 32 and 64 bit kernels, due 13467c478bd9Sstevel@tonic-gate * to the presence of a timeval structure, which contains longs, 13477c478bd9Sstevel@tonic-gate * in the if_data structure. Anyway, we know where the message ends, 13487c478bd9Sstevel@tonic-gate * so we work backwards to get the start of the sockaddr_dl structure. 13497c478bd9Sstevel@tonic-gate */ 13507c478bd9Sstevel@tonic-gate /*LINTED*/ 13517c478bd9Sstevel@tonic-gate sdl = (struct sockaddr_dl *)((char *)ifm + ifm->ifm_msglen - 13527c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_dl)); 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate assert(sdl->sdl_family == AF_LINK); 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate /* 13577c478bd9Sstevel@tonic-gate * The interface name is in sdl_data. 13587c478bd9Sstevel@tonic-gate * RTM_IFINFO messages are only generated for logical interface 13597c478bd9Sstevel@tonic-gate * zero, so there is no colon and logical interface number to 13607c478bd9Sstevel@tonic-gate * strip from the name. The name is not null terminated, but 13617c478bd9Sstevel@tonic-gate * there should be enough space in sdl_data to add the null. 13627c478bd9Sstevel@tonic-gate */ 13637c478bd9Sstevel@tonic-gate if (sdl->sdl_nlen >= sizeof (sdl->sdl_data)) { 13647c478bd9Sstevel@tonic-gate if (debug & D_LINKNOTE) 1365e6ed03fcSmeem logdebug("process_rtm_ifinfo: phyint name too long\n"); 13667c478bd9Sstevel@tonic-gate return (_B_TRUE); 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate sdl->sdl_data[sdl->sdl_nlen] = 0; 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate pi = phyint_lookup(sdl->sdl_data); 13717c478bd9Sstevel@tonic-gate if (pi == NULL) { 13727c478bd9Sstevel@tonic-gate if (debug & D_LINKNOTE) 13737c478bd9Sstevel@tonic-gate logdebug("process_rtm_ifinfo: phyint lookup failed" 13747c478bd9Sstevel@tonic-gate " for %s\n", sdl->sdl_data); 13757c478bd9Sstevel@tonic-gate return (_B_TRUE); 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate /* 13797c478bd9Sstevel@tonic-gate * We want to try and avoid doing a full interface scan for 1380e11c3f44Smeem * link state notifications from the datalink layer, as indicated 13817c478bd9Sstevel@tonic-gate * by the state of the IFF_RUNNING flag. If just the 13827c478bd9Sstevel@tonic-gate * IFF_RUNNING flag has changed state, the link state changes 13837c478bd9Sstevel@tonic-gate * are processed without a full scan. 13847c478bd9Sstevel@tonic-gate * If there is both an IPv4 and IPv6 instance associated with 13857c478bd9Sstevel@tonic-gate * the physical interface, we will get an RTM_IFINFO message 13867c478bd9Sstevel@tonic-gate * for each instance. If we just maintained a single copy of 13877c478bd9Sstevel@tonic-gate * the physical interface flags, it would appear that no flags 13887c478bd9Sstevel@tonic-gate * had changed when the second message is processed, leading us 13897c478bd9Sstevel@tonic-gate * to believe that the message wasn't generated by a flags change, 13907c478bd9Sstevel@tonic-gate * and that a full interface scan is required. 13917c478bd9Sstevel@tonic-gate * To get around this problem, two additional copies of the flags 13927c478bd9Sstevel@tonic-gate * are kept, one copy for each instance. These are only used in 13937c478bd9Sstevel@tonic-gate * this routine. At any one time, all three copies of the flags 13947c478bd9Sstevel@tonic-gate * should be identical except for the IFF_RUNNING flag. The 13957c478bd9Sstevel@tonic-gate * copy of the flags in the "phyint" structure is always up to 13967c478bd9Sstevel@tonic-gate * date. 13977c478bd9Sstevel@tonic-gate */ 13987c478bd9Sstevel@tonic-gate pii = (type == AF_INET) ? pi->pi_v4 : pi->pi_v6; 13997c478bd9Sstevel@tonic-gate if (pii == NULL) { 14007c478bd9Sstevel@tonic-gate if (debug & D_LINKNOTE) 14017c478bd9Sstevel@tonic-gate logdebug("process_rtm_ifinfo: no instance of address " 14027c478bd9Sstevel@tonic-gate "family %s for %s\n", AF_STR(type), pi->pi_name); 14037c478bd9Sstevel@tonic-gate return (_B_TRUE); 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate old_flags = pii->pii_flags; 14077c478bd9Sstevel@tonic-gate pii->pii_flags = PHYINT_FLAGS(ifm->ifm_flags); 14087c478bd9Sstevel@tonic-gate pi->pi_flags = pii->pii_flags; 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate if (debug & D_LINKNOTE) { 14117c478bd9Sstevel@tonic-gate logdebug("process_rtm_ifinfo: %s address family: %s, " 14127c478bd9Sstevel@tonic-gate "old flags: %llx, new flags: %llx\n", pi->pi_name, 14137c478bd9Sstevel@tonic-gate AF_STR(type), old_flags, pi->pi_flags); 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate /* 14177c478bd9Sstevel@tonic-gate * If IFF_STANDBY has changed, indicate that the interface has changed 14189bea6098Smeem * types and refresh IFF_INACTIVE if need be. 14197c478bd9Sstevel@tonic-gate */ 14209bea6098Smeem if ((old_flags ^ pii->pii_flags) & IFF_STANDBY) { 1421e11c3f44Smeem phyint_changed(pi); 14229bea6098Smeem if (pii->pii_flags & IFF_STANDBY) 14239bea6098Smeem phyint_standby_refresh_inactive(pi); 14249bea6098Smeem } 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate /* Has just the IFF_RUNNING flag changed state ? */ 14277c478bd9Sstevel@tonic-gate if ((old_flags ^ pii->pii_flags) != IFF_RUNNING) { 14287c478bd9Sstevel@tonic-gate struct phyint_instance *pii_other; 14297c478bd9Sstevel@tonic-gate /* 14307c478bd9Sstevel@tonic-gate * It wasn't just a link state change. Update 14317c478bd9Sstevel@tonic-gate * the other instance's copy of the flags. 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate pii_other = phyint_inst_other(pii); 14347c478bd9Sstevel@tonic-gate if (pii_other != NULL) 14357c478bd9Sstevel@tonic-gate pii_other->pii_flags = pii->pii_flags; 14367c478bd9Sstevel@tonic-gate return (_B_TRUE); 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate return (_B_FALSE); 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate /* 14437c478bd9Sstevel@tonic-gate * Retrieve as many routing socket messages as possible, and try to 14447c478bd9Sstevel@tonic-gate * empty the routing sockets. Initiate full scan of targets or interfaces 14457c478bd9Sstevel@tonic-gate * as needed. 14467c478bd9Sstevel@tonic-gate * We listen on separate IPv4 an IPv6 sockets so that we can accurately 14477c478bd9Sstevel@tonic-gate * detect changes in certain flags (see "process_rtm_ifinfo()" above). 14487c478bd9Sstevel@tonic-gate */ 14497c478bd9Sstevel@tonic-gate static void 14507c478bd9Sstevel@tonic-gate process_rtsock(int rtsock_v4, int rtsock_v6) 14517c478bd9Sstevel@tonic-gate { 14527c478bd9Sstevel@tonic-gate int nbytes; 14537c478bd9Sstevel@tonic-gate int64_t msg[2048 / 8]; 14547c478bd9Sstevel@tonic-gate struct rt_msghdr *rtm; 14557c478bd9Sstevel@tonic-gate boolean_t need_if_scan = _B_FALSE; 14567c478bd9Sstevel@tonic-gate boolean_t need_rt_scan = _B_FALSE; 14577c478bd9Sstevel@tonic-gate boolean_t rtm_ifinfo_seen = _B_FALSE; 14587c478bd9Sstevel@tonic-gate int type; 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate /* Read as many messages as possible and try to empty the sockets */ 14617c478bd9Sstevel@tonic-gate for (type = AF_INET; ; type = AF_INET6) { 14627c478bd9Sstevel@tonic-gate for (;;) { 14637c478bd9Sstevel@tonic-gate nbytes = read((type == AF_INET) ? rtsock_v4 : 14647c478bd9Sstevel@tonic-gate rtsock_v6, msg, sizeof (msg)); 14657c478bd9Sstevel@tonic-gate if (nbytes <= 0) { 14667c478bd9Sstevel@tonic-gate /* No more messages */ 14677c478bd9Sstevel@tonic-gate break; 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate rtm = (struct rt_msghdr *)msg; 14707c478bd9Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 14717c478bd9Sstevel@tonic-gate logerr("process_rtsock: version %d " 14727c478bd9Sstevel@tonic-gate "not understood\n", rtm->rtm_version); 14737c478bd9Sstevel@tonic-gate break; 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate if (debug & D_PHYINT) { 14777c478bd9Sstevel@tonic-gate logdebug("process_rtsock: message %d\n", 14787c478bd9Sstevel@tonic-gate rtm->rtm_type); 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate switch (rtm->rtm_type) { 14827c478bd9Sstevel@tonic-gate case RTM_NEWADDR: 14837c478bd9Sstevel@tonic-gate case RTM_DELADDR: 14847c478bd9Sstevel@tonic-gate /* 14857c478bd9Sstevel@tonic-gate * Some logical interface has changed, 14867c478bd9Sstevel@tonic-gate * have to scan everything to determine 14877c478bd9Sstevel@tonic-gate * what actually changed. 14887c478bd9Sstevel@tonic-gate */ 14897c478bd9Sstevel@tonic-gate need_if_scan = _B_TRUE; 14907c478bd9Sstevel@tonic-gate break; 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate case RTM_IFINFO: 14937c478bd9Sstevel@tonic-gate rtm_ifinfo_seen = _B_TRUE; 1494e6ed03fcSmeem need_if_scan |= process_rtm_ifinfo( 1495e6ed03fcSmeem (if_msghdr_t *)rtm, type); 14967c478bd9Sstevel@tonic-gate break; 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate case RTM_ADD: 14997c478bd9Sstevel@tonic-gate case RTM_DELETE: 15007c478bd9Sstevel@tonic-gate case RTM_CHANGE: 15017c478bd9Sstevel@tonic-gate case RTM_OLDADD: 15027c478bd9Sstevel@tonic-gate case RTM_OLDDEL: 15037c478bd9Sstevel@tonic-gate need_rt_scan = _B_TRUE; 15047c478bd9Sstevel@tonic-gate break; 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate default: 15077c478bd9Sstevel@tonic-gate /* Not interesting */ 15087c478bd9Sstevel@tonic-gate break; 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate if (type == AF_INET6) 15127c478bd9Sstevel@tonic-gate break; 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate if (need_if_scan) { 15167c478bd9Sstevel@tonic-gate if (debug & D_LINKNOTE && rtm_ifinfo_seen) 15177c478bd9Sstevel@tonic-gate logdebug("process_rtsock: synchronizing with kernel\n"); 15187c478bd9Sstevel@tonic-gate initifs(); 15197c478bd9Sstevel@tonic-gate } else if (rtm_ifinfo_seen) { 15207c478bd9Sstevel@tonic-gate if (debug & D_LINKNOTE) 15217c478bd9Sstevel@tonic-gate logdebug("process_rtsock: " 15227c478bd9Sstevel@tonic-gate "link up/down notification(s) seen\n"); 15237c478bd9Sstevel@tonic-gate process_link_state_changes(); 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate 15267c478bd9Sstevel@tonic-gate if (need_rt_scan) 15277c478bd9Sstevel@tonic-gate init_router_targets(); 15287c478bd9Sstevel@tonic-gate } 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate /* 15317c478bd9Sstevel@tonic-gate * Look if the phyint instance or one of its logints have been removed from 15327c478bd9Sstevel@tonic-gate * the kernel and take appropriate action. 15337c478bd9Sstevel@tonic-gate * Uses {pii,li}_in_use. 15347c478bd9Sstevel@tonic-gate */ 15357c478bd9Sstevel@tonic-gate static void 15367c478bd9Sstevel@tonic-gate check_if_removed(struct phyint_instance *pii) 15377c478bd9Sstevel@tonic-gate { 15387c478bd9Sstevel@tonic-gate struct logint *li; 15397c478bd9Sstevel@tonic-gate struct logint *next_li; 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate /* Detect phyints that have been removed from the kernel. */ 15427c478bd9Sstevel@tonic-gate if (!pii->pii_in_use) { 15437c478bd9Sstevel@tonic-gate logtrace("%s %s has been removed from kernel\n", 15447c478bd9Sstevel@tonic-gate AF_STR(pii->pii_af), pii->pii_phyint->pi_name); 15457c478bd9Sstevel@tonic-gate phyint_inst_delete(pii); 15467c478bd9Sstevel@tonic-gate } else { 15477c478bd9Sstevel@tonic-gate /* Detect logints that have been removed. */ 15487c478bd9Sstevel@tonic-gate for (li = pii->pii_logint; li != NULL; li = next_li) { 15497c478bd9Sstevel@tonic-gate next_li = li->li_next; 15507c478bd9Sstevel@tonic-gate if (!li->li_in_use) { 15517c478bd9Sstevel@tonic-gate logint_delete(li); 15527c478bd9Sstevel@tonic-gate } 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate } 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate /* 155827438c18SJon Anderson * Parse the supplied mib2 information to extract the routing information 155927438c18SJon Anderson * table. Process the routing table to get the list of known onlink routers 156027438c18SJon Anderson * and update our database. These onlink routers will serve as probe 156127438c18SJon Anderson * targets. 15627c478bd9Sstevel@tonic-gate */ 156327438c18SJon Anderson static void 156427438c18SJon Anderson update_router_list(mib_item_t *item) 15657c478bd9Sstevel@tonic-gate { 156627438c18SJon Anderson for (; item != NULL; item = item->mi_next) { 156727438c18SJon Anderson if (item->mi_opthdr.name == 0) 15687c478bd9Sstevel@tonic-gate continue; 156927438c18SJon Anderson if (item->mi_opthdr.level == MIB2_IP && 157027438c18SJon Anderson item->mi_opthdr.name == MIB2_IP_ROUTE) { 157127438c18SJon Anderson ire_process_v4((mib2_ipRouteEntry_t *)item->mi_valp, 157227438c18SJon Anderson item->mi_opthdr.len); 157327438c18SJon Anderson } else if (item->mi_opthdr.level == MIB2_IP6 && 157427438c18SJon Anderson item->mi_opthdr.name == MIB2_IP6_ROUTE) { 157527438c18SJon Anderson ire_process_v6((mib2_ipv6RouteEntry_t *)item->mi_valp, 157627438c18SJon Anderson item->mi_opthdr.len); 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate } 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate 1581e11c3f44Smeem 15827c478bd9Sstevel@tonic-gate /* 1583e11c3f44Smeem * Convert octet `octp' to a phyint name and store in `ifname' 1584e11c3f44Smeem */ 1585e11c3f44Smeem static void 1586e11c3f44Smeem oct2ifname(const Octet_t *octp, char *ifname, size_t ifsize) 1587e11c3f44Smeem { 1588e11c3f44Smeem char *cp; 1589e11c3f44Smeem size_t len = MIN(octp->o_length, ifsize - 1); 1590e11c3f44Smeem 1591e11c3f44Smeem (void) strncpy(ifname, octp->o_bytes, len); 1592e11c3f44Smeem ifname[len] = '\0'; 1593e11c3f44Smeem 1594e11c3f44Smeem if ((cp = strchr(ifname, IF_SEPARATOR)) != NULL) 1595e11c3f44Smeem *cp = '\0'; 1596e11c3f44Smeem } 1597e11c3f44Smeem 1598e11c3f44Smeem /* 1599e11c3f44Smeem * Examine the IPv4 routing table `buf' for possible targets. For each 1600e11c3f44Smeem * possible target, if it's on the same subnet an interface route, pass 1601e11c3f44Smeem * it to router_add_common() for further consideration. 16027c478bd9Sstevel@tonic-gate */ 16037c478bd9Sstevel@tonic-gate static void 16047c478bd9Sstevel@tonic-gate ire_process_v4(mib2_ipRouteEntry_t *buf, size_t len) 16057c478bd9Sstevel@tonic-gate { 1606e11c3f44Smeem char ifname[LIFNAMSIZ]; 1607e11c3f44Smeem mib2_ipRouteEntry_t *rp, *rp1, *endp; 16087c478bd9Sstevel@tonic-gate struct in_addr nexthop_v4; 1609e11c3f44Smeem struct in6_addr nexthop; 16107c478bd9Sstevel@tonic-gate 161127438c18SJon Anderson if (debug & D_TARGET) 161227438c18SJon Anderson logdebug("ire_process_v4(len %d)\n", len); 161327438c18SJon Anderson 16147c478bd9Sstevel@tonic-gate if (len == 0) 16157c478bd9Sstevel@tonic-gate return; 16167c478bd9Sstevel@tonic-gate 161727438c18SJon Anderson assert((len % ipRouteEntrySize) == 0); 161827438c18SJon Anderson endp = buf + (len / ipRouteEntrySize); 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate /* 1621e11c3f44Smeem * Scan the routing table entries for any IRE_OFFSUBNET entries, and 1622e11c3f44Smeem * cross-reference them with the interface routes to determine if 1623e11c3f44Smeem * they're possible probe targets. 16247c478bd9Sstevel@tonic-gate */ 16257c478bd9Sstevel@tonic-gate for (rp = buf; rp < endp; rp++) { 16267c478bd9Sstevel@tonic-gate if (!(rp->ipRouteInfo.re_ire_type & IRE_OFFSUBNET)) 16277c478bd9Sstevel@tonic-gate continue; 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate /* Get the nexthop address. */ 16307c478bd9Sstevel@tonic-gate nexthop_v4.s_addr = rp->ipRouteNextHop; 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate /* 1633e11c3f44Smeem * Rescan the routing table looking for interface routes that 1634e11c3f44Smeem * are on the same subnet, and try to add them. If they're 1635e11c3f44Smeem * not relevant (e.g., the interface route isn't part of an 1636e11c3f44Smeem * IPMP group, router_add_common() will discard). 16377c478bd9Sstevel@tonic-gate */ 16387c478bd9Sstevel@tonic-gate for (rp1 = buf; rp1 < endp; rp1++) { 1639e11c3f44Smeem if (!(rp1->ipRouteInfo.re_ire_type & IRE_INTERFACE) || 1640e11c3f44Smeem rp1->ipRouteIfIndex.o_length == 0) 16417c478bd9Sstevel@tonic-gate continue; 16427c478bd9Sstevel@tonic-gate 1643e11c3f44Smeem if ((rp1->ipRouteDest & rp1->ipRouteMask) != 1644e11c3f44Smeem (nexthop_v4.s_addr & rp1->ipRouteMask)) 1645e11c3f44Smeem continue; 16467c478bd9Sstevel@tonic-gate 1647e11c3f44Smeem oct2ifname(&rp1->ipRouteIfIndex, ifname, LIFNAMSIZ); 16487c478bd9Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&nexthop_v4, &nexthop); 16497c478bd9Sstevel@tonic-gate router_add_common(AF_INET, ifname, nexthop); 16507c478bd9Sstevel@tonic-gate } 1651e11c3f44Smeem } 1652e11c3f44Smeem } 16537c478bd9Sstevel@tonic-gate 16547c478bd9Sstevel@tonic-gate void 16557c478bd9Sstevel@tonic-gate router_add_common(int af, char *ifname, struct in6_addr nexthop) 16567c478bd9Sstevel@tonic-gate { 16577c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 16587c478bd9Sstevel@tonic-gate struct phyint *pi; 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate if (debug & D_TARGET) 16617c478bd9Sstevel@tonic-gate logdebug("router_add_common(%s %s)\n", AF_STR(af), ifname); 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate /* 16647c478bd9Sstevel@tonic-gate * Retrieve the phyint instance; bail if it's not known to us yet. 16657c478bd9Sstevel@tonic-gate */ 16667c478bd9Sstevel@tonic-gate pii = phyint_inst_lookup(af, ifname); 16677c478bd9Sstevel@tonic-gate if (pii == NULL) 16687c478bd9Sstevel@tonic-gate return; 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate /* 16717c478bd9Sstevel@tonic-gate * Don't use our own addresses as targets. 16727c478bd9Sstevel@tonic-gate */ 167387e66ffcSrk129064 if (own_address(nexthop)) 16747c478bd9Sstevel@tonic-gate return; 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate /* 16777c478bd9Sstevel@tonic-gate * If the phyint is part a named group, then add the address to all 16787c478bd9Sstevel@tonic-gate * members of the group; note that this is suboptimal in the IPv4 case 16797c478bd9Sstevel@tonic-gate * as it has already been added to all matching interfaces in 16807c478bd9Sstevel@tonic-gate * ire_process_v4(). Otherwise, add the address only to the phyint 16817c478bd9Sstevel@tonic-gate * itself, since other phyints in the anongroup may not be on the same 16827c478bd9Sstevel@tonic-gate * subnet. 16837c478bd9Sstevel@tonic-gate */ 16847c478bd9Sstevel@tonic-gate pi = pii->pii_phyint; 16857c478bd9Sstevel@tonic-gate if (pi->pi_group == phyint_anongroup) { 16867c478bd9Sstevel@tonic-gate target_add(pii, nexthop, _B_TRUE); 16877c478bd9Sstevel@tonic-gate } else { 16887c478bd9Sstevel@tonic-gate pi = pi->pi_group->pg_phyint; 16897c478bd9Sstevel@tonic-gate for (; pi != NULL; pi = pi->pi_pgnext) 16907c478bd9Sstevel@tonic-gate target_add(PHYINT_INSTANCE(pi, af), nexthop, _B_TRUE); 16917c478bd9Sstevel@tonic-gate } 16927c478bd9Sstevel@tonic-gate } 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate /* 1695e11c3f44Smeem * Examine the IPv6 routing table `buf' for possible link-local targets, and 1696e11c3f44Smeem * pass any contenders to router_add_common() for further consideration. 16977c478bd9Sstevel@tonic-gate */ 16987c478bd9Sstevel@tonic-gate static void 16997c478bd9Sstevel@tonic-gate ire_process_v6(mib2_ipv6RouteEntry_t *buf, size_t len) 17007c478bd9Sstevel@tonic-gate { 1701e11c3f44Smeem struct lifreq lifr; 1702e11c3f44Smeem char ifname[LIFNAMSIZ]; 1703e11c3f44Smeem char grname[LIFGRNAMSIZ]; 1704e11c3f44Smeem mib2_ipv6RouteEntry_t *rp, *rp1, *endp; 17057c478bd9Sstevel@tonic-gate struct in6_addr nexthop_v6; 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate if (debug & D_TARGET) 17087c478bd9Sstevel@tonic-gate logdebug("ire_process_v6(len %d)\n", len); 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate if (len == 0) 17117c478bd9Sstevel@tonic-gate return; 17127c478bd9Sstevel@tonic-gate 171327438c18SJon Anderson assert((len % ipv6RouteEntrySize) == 0); 171427438c18SJon Anderson endp = buf + (len / ipv6RouteEntrySize); 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate /* 1717e11c3f44Smeem * Scan the routing table entries for any IRE_OFFSUBNET entries, and 1718e11c3f44Smeem * cross-reference them with the interface routes to determine if 1719e11c3f44Smeem * they're possible probe targets. 17207c478bd9Sstevel@tonic-gate */ 17217c478bd9Sstevel@tonic-gate for (rp = buf; rp < endp; rp++) { 1722e11c3f44Smeem if (!(rp->ipv6RouteInfo.re_ire_type & IRE_OFFSUBNET) || 1723e11c3f44Smeem !IN6_IS_ADDR_LINKLOCAL(&rp->ipv6RouteNextHop)) 17247c478bd9Sstevel@tonic-gate continue; 17257c478bd9Sstevel@tonic-gate 1726e11c3f44Smeem /* Get the nexthop address. */ 17277c478bd9Sstevel@tonic-gate nexthop_v6 = rp->ipv6RouteNextHop; 1728e11c3f44Smeem 17297c478bd9Sstevel@tonic-gate /* 1730e11c3f44Smeem * The interface name should always exist for link-locals; 1731e11c3f44Smeem * we use it to map this entry to an IPMP group name. 17327c478bd9Sstevel@tonic-gate */ 1733e11c3f44Smeem if (rp->ipv6RouteIfIndex.o_length == 0) 1734e11c3f44Smeem continue; 1735e11c3f44Smeem 1736e11c3f44Smeem oct2ifname(&rp->ipv6RouteIfIndex, lifr.lifr_name, LIFNAMSIZ); 1737e11c3f44Smeem if (ioctl(ifsock_v6, SIOCGLIFGROUPNAME, &lifr) == -1 || 1738e11c3f44Smeem strlcpy(grname, lifr.lifr_groupname, LIFGRNAMSIZ) == 0) { 1739e11c3f44Smeem continue; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate 1742e11c3f44Smeem /* 1743e11c3f44Smeem * Rescan the list of routes for interface routes, and add the 1744e11c3f44Smeem * above target to any interfaces in the same IPMP group. 1745e11c3f44Smeem */ 1746e11c3f44Smeem for (rp1 = buf; rp1 < endp; rp1++) { 1747e11c3f44Smeem if (!(rp1->ipv6RouteInfo.re_ire_type & IRE_INTERFACE) || 1748e11c3f44Smeem rp1->ipv6RouteIfIndex.o_length == 0) { 1749e11c3f44Smeem continue; 1750e11c3f44Smeem } 1751e11c3f44Smeem oct2ifname(&rp1->ipv6RouteIfIndex, ifname, LIFNAMSIZ); 1752e11c3f44Smeem (void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ); 17537c478bd9Sstevel@tonic-gate 1754e11c3f44Smeem if (ioctl(ifsock_v6, SIOCGLIFGROUPNAME, &lifr) != -1 && 1755e11c3f44Smeem strcmp(lifr.lifr_groupname, grname) == 0) { 17567c478bd9Sstevel@tonic-gate router_add_common(AF_INET6, ifname, nexthop_v6); 17577c478bd9Sstevel@tonic-gate } 1758e11c3f44Smeem } 1759e11c3f44Smeem } 1760e11c3f44Smeem } 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate /* 17637c478bd9Sstevel@tonic-gate * Build a list of target routers, by scanning the routing tables. 17647c478bd9Sstevel@tonic-gate * It is assumed that interface routes exist, to reach the routers. 17657c478bd9Sstevel@tonic-gate */ 17667c478bd9Sstevel@tonic-gate static void 17677c478bd9Sstevel@tonic-gate init_router_targets(void) 17687c478bd9Sstevel@tonic-gate { 17697c478bd9Sstevel@tonic-gate struct target *tg; 17707c478bd9Sstevel@tonic-gate struct target *next_tg; 17717c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 17727c478bd9Sstevel@tonic-gate struct phyint *pi; 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate if (force_mcast) 17757c478bd9Sstevel@tonic-gate return; 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) { 17787c478bd9Sstevel@tonic-gate pi = pii->pii_phyint; 17797c478bd9Sstevel@tonic-gate /* 1780e11c3f44Smeem * Set tg_in_use to false only for router targets. 17817c478bd9Sstevel@tonic-gate */ 1782e11c3f44Smeem if (!pii->pii_targets_are_routers) 17837c478bd9Sstevel@tonic-gate continue; 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) 17867c478bd9Sstevel@tonic-gate tg->tg_in_use = 0; 17877c478bd9Sstevel@tonic-gate } 17887c478bd9Sstevel@tonic-gate 178927438c18SJon Anderson if (mibwalk(update_router_list) == -1) 17907c478bd9Sstevel@tonic-gate exit(1); 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) { 1793e11c3f44Smeem pi = pii->pii_phyint; 1794e11c3f44Smeem if (!pii->pii_targets_are_routers) 17957c478bd9Sstevel@tonic-gate continue; 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate for (tg = pii->pii_targets; tg != NULL; tg = next_tg) { 17987c478bd9Sstevel@tonic-gate next_tg = tg->tg_next; 1799e11c3f44Smeem /* 1800e11c3f44Smeem * If the group has failed, it's likely the route was 1801e11c3f44Smeem * removed by an application affected by that failure. 1802e11c3f44Smeem * In that case, we keep the target so that we can 1803e11c3f44Smeem * reliably repair, at which point we'll refresh the 1804e11c3f44Smeem * target list again. 1805e11c3f44Smeem */ 1806e11c3f44Smeem if (!tg->tg_in_use && !GROUP_FAILED(pi->pi_group)) 18077c478bd9Sstevel@tonic-gate target_delete(tg); 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate } 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate /* 18137c478bd9Sstevel@tonic-gate * Attempt to assign host targets to any interfaces that do not currently 18147c478bd9Sstevel@tonic-gate * have probe targets by sharing targets with other interfaces in the group. 18157c478bd9Sstevel@tonic-gate */ 18167c478bd9Sstevel@tonic-gate static void 18177c478bd9Sstevel@tonic-gate init_host_targets(void) 18187c478bd9Sstevel@tonic-gate { 18197c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 18207c478bd9Sstevel@tonic-gate struct phyint_group *pg; 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) { 18237c478bd9Sstevel@tonic-gate pg = pii->pii_phyint->pi_group; 18247c478bd9Sstevel@tonic-gate if (pg != phyint_anongroup && pii->pii_targets == NULL) 18257c478bd9Sstevel@tonic-gate dup_host_targets(pii); 18267c478bd9Sstevel@tonic-gate } 18277c478bd9Sstevel@tonic-gate } 18287c478bd9Sstevel@tonic-gate 18297c478bd9Sstevel@tonic-gate /* 18307c478bd9Sstevel@tonic-gate * Duplicate host targets from other phyints of the group to 18317c478bd9Sstevel@tonic-gate * the phyint instance 'desired_pii'. 18327c478bd9Sstevel@tonic-gate */ 18337c478bd9Sstevel@tonic-gate static void 18347c478bd9Sstevel@tonic-gate dup_host_targets(struct phyint_instance *desired_pii) 18357c478bd9Sstevel@tonic-gate { 18367c478bd9Sstevel@tonic-gate int af; 18377c478bd9Sstevel@tonic-gate struct phyint *pi; 18387c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 18397c478bd9Sstevel@tonic-gate struct target *tg; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate assert(desired_pii->pii_phyint->pi_group != phyint_anongroup); 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate af = desired_pii->pii_af; 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate /* 18467c478bd9Sstevel@tonic-gate * For every phyint in the same group as desired_pii, check if 18477c478bd9Sstevel@tonic-gate * it has any host targets. If so add them to desired_pii. 18487c478bd9Sstevel@tonic-gate */ 18497c478bd9Sstevel@tonic-gate for (pi = desired_pii->pii_phyint; pi != NULL; pi = pi->pi_pgnext) { 18507c478bd9Sstevel@tonic-gate pii = PHYINT_INSTANCE(pi, af); 18517c478bd9Sstevel@tonic-gate /* 18527c478bd9Sstevel@tonic-gate * We know that we don't have targets on this phyint instance 18537c478bd9Sstevel@tonic-gate * since we have been called. But we still check for 18547c478bd9Sstevel@tonic-gate * pii_targets_are_routers because another phyint instance 18557c478bd9Sstevel@tonic-gate * could have router targets, since IFF_NOFAILOVER addresses 18567c478bd9Sstevel@tonic-gate * on different phyint instances may belong to different 18577c478bd9Sstevel@tonic-gate * subnets. 18587c478bd9Sstevel@tonic-gate */ 18597c478bd9Sstevel@tonic-gate if ((pii == NULL) || (pii == desired_pii) || 18607c478bd9Sstevel@tonic-gate pii->pii_targets_are_routers) 18617c478bd9Sstevel@tonic-gate continue; 18627c478bd9Sstevel@tonic-gate for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) { 18637c478bd9Sstevel@tonic-gate target_create(desired_pii, tg->tg_address, _B_FALSE); 18647c478bd9Sstevel@tonic-gate } 18657c478bd9Sstevel@tonic-gate } 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate static void 18697c478bd9Sstevel@tonic-gate usage(char *cmd) 18707c478bd9Sstevel@tonic-gate { 18717c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "usage: %s\n", cmd); 18727c478bd9Sstevel@tonic-gate } 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate #define MPATHD_DEFAULT_FILE "/etc/default/mpathd" 18767c478bd9Sstevel@tonic-gate 18777c478bd9Sstevel@tonic-gate /* Get an option from the /etc/default/mpathd file */ 18787c478bd9Sstevel@tonic-gate static char * 18797c478bd9Sstevel@tonic-gate getdefault(char *name) 18807c478bd9Sstevel@tonic-gate { 18817c478bd9Sstevel@tonic-gate char namebuf[BUFSIZ]; 18827c478bd9Sstevel@tonic-gate char *value = NULL; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate if (defopen(MPATHD_DEFAULT_FILE) == 0) { 18857c478bd9Sstevel@tonic-gate char *cp; 18867c478bd9Sstevel@tonic-gate int flags; 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate /* 18897c478bd9Sstevel@tonic-gate * ignore case 18907c478bd9Sstevel@tonic-gate */ 18917c478bd9Sstevel@tonic-gate flags = defcntl(DC_GETFLAGS, 0); 18927c478bd9Sstevel@tonic-gate TURNOFF(flags, DC_CASE); 18937c478bd9Sstevel@tonic-gate (void) defcntl(DC_SETFLAGS, flags); 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate /* Add "=" to the name */ 18967c478bd9Sstevel@tonic-gate (void) strncpy(namebuf, name, sizeof (namebuf) - 2); 18977c478bd9Sstevel@tonic-gate (void) strncat(namebuf, "=", 2); 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate if ((cp = defread(namebuf)) != NULL) 19007c478bd9Sstevel@tonic-gate value = strdup(cp); 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate /* close */ 19037c478bd9Sstevel@tonic-gate (void) defopen((char *)NULL); 19047c478bd9Sstevel@tonic-gate } 19057c478bd9Sstevel@tonic-gate return (value); 19067c478bd9Sstevel@tonic-gate } 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate /* 19107c478bd9Sstevel@tonic-gate * Command line options below 19117c478bd9Sstevel@tonic-gate */ 19127c478bd9Sstevel@tonic-gate boolean_t failback_enabled = _B_TRUE; /* failback enabled/disabled */ 1913e11c3f44Smeem boolean_t track_all_phyints = _B_FALSE; /* track all IP interfaces */ 19147c478bd9Sstevel@tonic-gate static boolean_t adopt = _B_FALSE; 19157c478bd9Sstevel@tonic-gate static boolean_t foreground = _B_FALSE; 19167c478bd9Sstevel@tonic-gate 19177c478bd9Sstevel@tonic-gate int 19187c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 19197c478bd9Sstevel@tonic-gate { 19207c478bd9Sstevel@tonic-gate int i; 19217c478bd9Sstevel@tonic-gate int c; 1922e11c3f44Smeem struct phyint *pi; 19237c478bd9Sstevel@tonic-gate struct phyint_instance *pii; 19247c478bd9Sstevel@tonic-gate char *value; 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate argv0 = argv; /* Saved for re-exec on SIGHUP */ 19277c478bd9Sstevel@tonic-gate srandom(gethostid()); /* Initialize the random number generator */ 19287c478bd9Sstevel@tonic-gate 19297c478bd9Sstevel@tonic-gate /* 19307c478bd9Sstevel@tonic-gate * NOTE: The messages output by in.mpathd are not suitable for 19317c478bd9Sstevel@tonic-gate * translation, so we do not call textdomain(). 19327c478bd9Sstevel@tonic-gate */ 19337c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate /* 19367c478bd9Sstevel@tonic-gate * Get the user specified value of 'failure detection time' 19377c478bd9Sstevel@tonic-gate * from /etc/default/mpathd 19387c478bd9Sstevel@tonic-gate */ 19397c478bd9Sstevel@tonic-gate value = getdefault("FAILURE_DETECTION_TIME"); 19407c478bd9Sstevel@tonic-gate if (value != NULL) { 19417c478bd9Sstevel@tonic-gate user_failure_detection_time = 19427c478bd9Sstevel@tonic-gate (int)strtol((char *)value, NULL, 0); 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate if (user_failure_detection_time <= 0) { 19457c478bd9Sstevel@tonic-gate user_failure_detection_time = FAILURE_DETECTION_TIME; 19467c478bd9Sstevel@tonic-gate logerr("Invalid failure detection time %s, assuming " 1947e11c3f44Smeem "default of %d ms\n", value, 1948e11c3f44Smeem user_failure_detection_time); 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate } else if (user_failure_detection_time < 19517c478bd9Sstevel@tonic-gate MIN_FAILURE_DETECTION_TIME) { 19527c478bd9Sstevel@tonic-gate user_failure_detection_time = 19537c478bd9Sstevel@tonic-gate MIN_FAILURE_DETECTION_TIME; 19547c478bd9Sstevel@tonic-gate logerr("Too small failure detection time of %s, " 1955e11c3f44Smeem "assuming minimum of %d ms\n", value, 19567c478bd9Sstevel@tonic-gate user_failure_detection_time); 19577c478bd9Sstevel@tonic-gate } 19587c478bd9Sstevel@tonic-gate free(value); 19597c478bd9Sstevel@tonic-gate } else { 19607c478bd9Sstevel@tonic-gate /* User has not specified the parameter, Use default value */ 19617c478bd9Sstevel@tonic-gate user_failure_detection_time = FAILURE_DETECTION_TIME; 19627c478bd9Sstevel@tonic-gate } 19637c478bd9Sstevel@tonic-gate 19647c478bd9Sstevel@tonic-gate /* 19657c478bd9Sstevel@tonic-gate * This gives the frequency at which probes will be sent. 19667c478bd9Sstevel@tonic-gate * When fdt ms elapses, we should be able to determine 19677c478bd9Sstevel@tonic-gate * whether 5 consecutive probes have failed or not. 19687c478bd9Sstevel@tonic-gate * 1 probe will be sent in every user_probe_interval ms, 19697c478bd9Sstevel@tonic-gate * randomly anytime in the (0.5 - 1.0) 2nd half of every 19707c478bd9Sstevel@tonic-gate * user_probe_interval. Thus when we send out probe 'n' we 19717c478bd9Sstevel@tonic-gate * can be sure that probe 'n - 2' is lost, if we have not 19727c478bd9Sstevel@tonic-gate * got the ack. (since the probe interval is > crtt). But 19737c478bd9Sstevel@tonic-gate * probe 'n - 1' may be a valid unacked probe, since the 19747c478bd9Sstevel@tonic-gate * time between 2 successive probes could be as small as 19757c478bd9Sstevel@tonic-gate * 0.5 * user_probe_interval. Hence the NUM_PROBE_FAILS + 2 19767c478bd9Sstevel@tonic-gate */ 19777c478bd9Sstevel@tonic-gate user_probe_interval = user_failure_detection_time / 19787c478bd9Sstevel@tonic-gate (NUM_PROBE_FAILS + 2); 19797c478bd9Sstevel@tonic-gate 19807c478bd9Sstevel@tonic-gate /* 19817c478bd9Sstevel@tonic-gate * Get the user specified value of failback_enabled from 19827c478bd9Sstevel@tonic-gate * /etc/default/mpathd 19837c478bd9Sstevel@tonic-gate */ 19847c478bd9Sstevel@tonic-gate value = getdefault("FAILBACK"); 19857c478bd9Sstevel@tonic-gate if (value != NULL) { 1986e11c3f44Smeem if (strcasecmp(value, "yes") == 0) 19877c478bd9Sstevel@tonic-gate failback_enabled = _B_TRUE; 1988e11c3f44Smeem else if (strcasecmp(value, "no") == 0) 19897c478bd9Sstevel@tonic-gate failback_enabled = _B_FALSE; 19907c478bd9Sstevel@tonic-gate else 19917c478bd9Sstevel@tonic-gate logerr("Invalid value for FAILBACK %s\n", value); 19927c478bd9Sstevel@tonic-gate free(value); 19937c478bd9Sstevel@tonic-gate } else { 19947c478bd9Sstevel@tonic-gate failback_enabled = _B_TRUE; 19957c478bd9Sstevel@tonic-gate } 19967c478bd9Sstevel@tonic-gate 19977c478bd9Sstevel@tonic-gate /* 19987c478bd9Sstevel@tonic-gate * Get the user specified value of track_all_phyints from 19997c478bd9Sstevel@tonic-gate * /etc/default/mpathd. The sense is reversed in 20007c478bd9Sstevel@tonic-gate * TRACK_INTERFACES_ONLY_WITH_GROUPS. 20017c478bd9Sstevel@tonic-gate */ 20027c478bd9Sstevel@tonic-gate value = getdefault("TRACK_INTERFACES_ONLY_WITH_GROUPS"); 20037c478bd9Sstevel@tonic-gate if (value != NULL) { 2004e11c3f44Smeem if (strcasecmp(value, "yes") == 0) 20057c478bd9Sstevel@tonic-gate track_all_phyints = _B_FALSE; 2006e11c3f44Smeem else if (strcasecmp(value, "no") == 0) 20077c478bd9Sstevel@tonic-gate track_all_phyints = _B_TRUE; 20087c478bd9Sstevel@tonic-gate else 20097c478bd9Sstevel@tonic-gate logerr("Invalid value for " 20107c478bd9Sstevel@tonic-gate "TRACK_INTERFACES_ONLY_WITH_GROUPS %s\n", value); 20117c478bd9Sstevel@tonic-gate free(value); 20127c478bd9Sstevel@tonic-gate } else { 20137c478bd9Sstevel@tonic-gate track_all_phyints = _B_FALSE; 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "adD:ml")) != EOF) { 20177c478bd9Sstevel@tonic-gate switch (c) { 20187c478bd9Sstevel@tonic-gate case 'a': 20197c478bd9Sstevel@tonic-gate adopt = _B_TRUE; 20207c478bd9Sstevel@tonic-gate break; 20217c478bd9Sstevel@tonic-gate case 'm': 20227c478bd9Sstevel@tonic-gate force_mcast = _B_TRUE; 20237c478bd9Sstevel@tonic-gate break; 20247c478bd9Sstevel@tonic-gate case 'd': 20257c478bd9Sstevel@tonic-gate debug = D_ALL; 20267c478bd9Sstevel@tonic-gate foreground = _B_TRUE; 20277c478bd9Sstevel@tonic-gate break; 20287c478bd9Sstevel@tonic-gate case 'D': 20297c478bd9Sstevel@tonic-gate i = (int)strtol(optarg, NULL, 0); 20307c478bd9Sstevel@tonic-gate if (i == 0) { 20317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Bad debug flags: %s\n", 20327c478bd9Sstevel@tonic-gate optarg); 20337c478bd9Sstevel@tonic-gate exit(1); 20347c478bd9Sstevel@tonic-gate } 20357c478bd9Sstevel@tonic-gate debug |= i; 20367c478bd9Sstevel@tonic-gate foreground = _B_TRUE; 20377c478bd9Sstevel@tonic-gate break; 20387c478bd9Sstevel@tonic-gate case 'l': 20397c478bd9Sstevel@tonic-gate /* 20407c478bd9Sstevel@tonic-gate * Turn off link state notification handling. 20417c478bd9Sstevel@tonic-gate * Undocumented command line flag, for debugging 20427c478bd9Sstevel@tonic-gate * purposes. 20437c478bd9Sstevel@tonic-gate */ 20447c478bd9Sstevel@tonic-gate handle_link_notifications = _B_FALSE; 20457c478bd9Sstevel@tonic-gate break; 20467c478bd9Sstevel@tonic-gate default: 20477c478bd9Sstevel@tonic-gate usage(argv[0]); 20487c478bd9Sstevel@tonic-gate exit(1); 20497c478bd9Sstevel@tonic-gate } 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate /* 20537c478bd9Sstevel@tonic-gate * The sockets for the loopback command interface should be listening 20547c478bd9Sstevel@tonic-gate * before we fork and exit in daemonize(). This way, whoever started us 20557c478bd9Sstevel@tonic-gate * can use the loopback interface as soon as they get a zero exit 20567c478bd9Sstevel@tonic-gate * status. 20577c478bd9Sstevel@tonic-gate */ 20587c478bd9Sstevel@tonic-gate lsock_v4 = setup_listener(AF_INET); 20597c478bd9Sstevel@tonic-gate lsock_v6 = setup_listener(AF_INET6); 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate if (lsock_v4 < 0 && lsock_v6 < 0) { 20627c478bd9Sstevel@tonic-gate logerr("main: setup_listener failed for both IPv4 and IPv6\n"); 20637c478bd9Sstevel@tonic-gate exit(1); 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate 20667c478bd9Sstevel@tonic-gate if (!foreground) { 20677c478bd9Sstevel@tonic-gate if (!daemonize()) { 20687c478bd9Sstevel@tonic-gate logerr("cannot daemonize\n"); 20697c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 20707c478bd9Sstevel@tonic-gate } 20717c478bd9Sstevel@tonic-gate initlog(); 20727c478bd9Sstevel@tonic-gate } 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate /* 20757c478bd9Sstevel@tonic-gate * Initializations: 20767c478bd9Sstevel@tonic-gate * 1. Create ifsock* sockets. These are used for performing SIOC* 20777c478bd9Sstevel@tonic-gate * ioctls. We have 2 sockets 1 each for IPv4 and IPv6. 20787c478bd9Sstevel@tonic-gate * 2. Initialize a pipe for handling/recording signal events. 20797c478bd9Sstevel@tonic-gate * 3. Create the routing sockets, used for listening 20807c478bd9Sstevel@tonic-gate * to routing / interface changes. 20817c478bd9Sstevel@tonic-gate * 4. phyint_init() - Initialize physical interface state 20827c478bd9Sstevel@tonic-gate * (in mpd_tables.c). Must be done before creating interfaces, 20837c478bd9Sstevel@tonic-gate * which timer_init() does indirectly. 208427438c18SJon Anderson * 5. Query kernel for route entry sizes (v4 and v6). 208527438c18SJon Anderson * 6. timer_init() - Initialize timer related stuff 208627438c18SJon Anderson * 7. initifs() - Initialize our database of all known interfaces 208727438c18SJon Anderson * 8. init_router_targets() - Initialize our database of all known 20887c478bd9Sstevel@tonic-gate * router targets. 20897c478bd9Sstevel@tonic-gate */ 20907c478bd9Sstevel@tonic-gate ifsock_v4 = socket(AF_INET, SOCK_DGRAM, 0); 20917c478bd9Sstevel@tonic-gate if (ifsock_v4 < 0) { 20927c478bd9Sstevel@tonic-gate logperror("main: IPv4 socket open"); 20937c478bd9Sstevel@tonic-gate exit(1); 20947c478bd9Sstevel@tonic-gate } 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate ifsock_v6 = socket(AF_INET6, SOCK_DGRAM, 0); 20977c478bd9Sstevel@tonic-gate if (ifsock_v6 < 0) { 20987c478bd9Sstevel@tonic-gate logperror("main: IPv6 socket open"); 20997c478bd9Sstevel@tonic-gate exit(1); 21007c478bd9Sstevel@tonic-gate } 21017c478bd9Sstevel@tonic-gate 21027c478bd9Sstevel@tonic-gate setup_eventpipe(); 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate rtsock_v4 = setup_rtsock(AF_INET); 21057c478bd9Sstevel@tonic-gate rtsock_v6 = setup_rtsock(AF_INET6); 21067c478bd9Sstevel@tonic-gate 21077c478bd9Sstevel@tonic-gate if (phyint_init() == -1) { 21087c478bd9Sstevel@tonic-gate logerr("cannot initialize physical interface structures"); 21097c478bd9Sstevel@tonic-gate exit(1); 21107c478bd9Sstevel@tonic-gate } 21117c478bd9Sstevel@tonic-gate 211227438c18SJon Anderson if (mibwalk(mib_get_constants) == -1) 211327438c18SJon Anderson exit(1); 211427438c18SJon Anderson 21157c478bd9Sstevel@tonic-gate timer_init(); 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate initifs(); 21187c478bd9Sstevel@tonic-gate 21197c478bd9Sstevel@tonic-gate /* 21207c478bd9Sstevel@tonic-gate * If we're operating in "adopt" mode and no interfaces need to be 21217c478bd9Sstevel@tonic-gate * tracked, shut down (ifconfig(1M) will restart us on demand if 21227c478bd9Sstevel@tonic-gate * interfaces are subsequently put into multipathing groups). 21237c478bd9Sstevel@tonic-gate */ 21247c478bd9Sstevel@tonic-gate if (adopt && phyint_instances == NULL) 21257c478bd9Sstevel@tonic-gate exit(0); 21267c478bd9Sstevel@tonic-gate 21277c478bd9Sstevel@tonic-gate /* 21287c478bd9Sstevel@tonic-gate * Main body. Keep listening for activity on any of the sockets 21297c478bd9Sstevel@tonic-gate * that we are monitoring and take appropriate action as necessary. 21307c478bd9Sstevel@tonic-gate * signals are also handled synchronously. 21317c478bd9Sstevel@tonic-gate */ 21327c478bd9Sstevel@tonic-gate for (;;) { 21337c478bd9Sstevel@tonic-gate if (poll(pollfds, pollfd_num, -1) < 0) { 21347c478bd9Sstevel@tonic-gate if (errno == EINTR) 21357c478bd9Sstevel@tonic-gate continue; 21367c478bd9Sstevel@tonic-gate logperror("main: poll"); 21377c478bd9Sstevel@tonic-gate exit(1); 21387c478bd9Sstevel@tonic-gate } 21397c478bd9Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 21407c478bd9Sstevel@tonic-gate if ((pollfds[i].fd == -1) || 21417c478bd9Sstevel@tonic-gate !(pollfds[i].revents & POLLIN)) 21427c478bd9Sstevel@tonic-gate continue; 21437c478bd9Sstevel@tonic-gate if (pollfds[i].fd == eventpipe_read) { 21447c478bd9Sstevel@tonic-gate in_signal(eventpipe_read); 21457c478bd9Sstevel@tonic-gate break; 21467c478bd9Sstevel@tonic-gate } 21477c478bd9Sstevel@tonic-gate if (pollfds[i].fd == rtsock_v4 || 21487c478bd9Sstevel@tonic-gate pollfds[i].fd == rtsock_v6) { 21497c478bd9Sstevel@tonic-gate process_rtsock(rtsock_v4, rtsock_v6); 21507c478bd9Sstevel@tonic-gate break; 21517c478bd9Sstevel@tonic-gate } 2152e11c3f44Smeem 21537c478bd9Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; 21547c478bd9Sstevel@tonic-gate pii = pii->pii_next) { 21557c478bd9Sstevel@tonic-gate if (pollfds[i].fd == pii->pii_probe_sock) { 21567c478bd9Sstevel@tonic-gate if (pii->pii_af == AF_INET) 21577c478bd9Sstevel@tonic-gate in_data(pii); 21587c478bd9Sstevel@tonic-gate else 21597c478bd9Sstevel@tonic-gate in6_data(pii); 21607c478bd9Sstevel@tonic-gate break; 21617c478bd9Sstevel@tonic-gate } 21627c478bd9Sstevel@tonic-gate } 2163e11c3f44Smeem 2164e11c3f44Smeem for (pi = phyints; pi != NULL; pi = pi->pi_next) { 2165e11c3f44Smeem if (pi->pi_notes != 0 && 2166e11c3f44Smeem pollfds[i].fd == dlpi_fd(pi->pi_dh)) { 2167e11c3f44Smeem (void) dlpi_recv(pi->pi_dh, NULL, NULL, 2168e11c3f44Smeem NULL, NULL, 0, NULL); 2169e11c3f44Smeem break; 2170e11c3f44Smeem } 2171e11c3f44Smeem } 2172e11c3f44Smeem 21737c478bd9Sstevel@tonic-gate if (pollfds[i].fd == lsock_v4) 21747c478bd9Sstevel@tonic-gate loopback_cmd(lsock_v4, AF_INET); 21757c478bd9Sstevel@tonic-gate else if (pollfds[i].fd == lsock_v6) 21767c478bd9Sstevel@tonic-gate loopback_cmd(lsock_v6, AF_INET6); 21777c478bd9Sstevel@tonic-gate } 21787c478bd9Sstevel@tonic-gate } 21797c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21807c478bd9Sstevel@tonic-gate return (EXIT_SUCCESS); 21817c478bd9Sstevel@tonic-gate } 21827c478bd9Sstevel@tonic-gate 21837c478bd9Sstevel@tonic-gate static int 21847c478bd9Sstevel@tonic-gate setup_listener(int af) 21857c478bd9Sstevel@tonic-gate { 21867c478bd9Sstevel@tonic-gate int sock; 21877c478bd9Sstevel@tonic-gate int on; 21887c478bd9Sstevel@tonic-gate int len; 21897c478bd9Sstevel@tonic-gate int ret; 21907c478bd9Sstevel@tonic-gate struct sockaddr_storage laddr; 21917c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 21927c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 21937c478bd9Sstevel@tonic-gate struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate assert(af == AF_INET || af == AF_INET6); 21967c478bd9Sstevel@tonic-gate 21977c478bd9Sstevel@tonic-gate sock = socket(af, SOCK_STREAM, 0); 21987c478bd9Sstevel@tonic-gate if (sock < 0) { 21997c478bd9Sstevel@tonic-gate logperror("setup_listener: socket"); 22007c478bd9Sstevel@tonic-gate exit(1); 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate on = 1; 22047c478bd9Sstevel@tonic-gate if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, 22057c478bd9Sstevel@tonic-gate sizeof (on)) < 0) { 22067c478bd9Sstevel@tonic-gate logperror("setup_listener: setsockopt (SO_REUSEADDR)"); 22077c478bd9Sstevel@tonic-gate exit(1); 22087c478bd9Sstevel@tonic-gate } 22097c478bd9Sstevel@tonic-gate 22107c478bd9Sstevel@tonic-gate bzero(&laddr, sizeof (laddr)); 22117c478bd9Sstevel@tonic-gate laddr.ss_family = af; 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate if (af == AF_INET) { 22147c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)&laddr; 22157c478bd9Sstevel@tonic-gate sin->sin_port = htons(MPATHD_PORT); 22167c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 22177c478bd9Sstevel@tonic-gate len = sizeof (struct sockaddr_in); 22187c478bd9Sstevel@tonic-gate } else { 22197c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&laddr; 22207c478bd9Sstevel@tonic-gate sin6->sin6_port = htons(MPATHD_PORT); 22217c478bd9Sstevel@tonic-gate sin6->sin6_addr = loopback_addr; 22227c478bd9Sstevel@tonic-gate len = sizeof (struct sockaddr_in6); 22237c478bd9Sstevel@tonic-gate } 22247c478bd9Sstevel@tonic-gate 22257c478bd9Sstevel@tonic-gate ret = bind(sock, (struct sockaddr *)&laddr, len); 22267c478bd9Sstevel@tonic-gate if (ret < 0) { 22277c478bd9Sstevel@tonic-gate if (errno == EADDRINUSE) { 22287c478bd9Sstevel@tonic-gate /* 22297c478bd9Sstevel@tonic-gate * Another instance of mpathd may be already active. 22307c478bd9Sstevel@tonic-gate */ 22317c478bd9Sstevel@tonic-gate logerr("main: is another instance of in.mpathd " 22327c478bd9Sstevel@tonic-gate "already active?\n"); 22337c478bd9Sstevel@tonic-gate exit(1); 22347c478bd9Sstevel@tonic-gate } else { 22357c478bd9Sstevel@tonic-gate (void) close(sock); 22367c478bd9Sstevel@tonic-gate return (-1); 22377c478bd9Sstevel@tonic-gate } 22387c478bd9Sstevel@tonic-gate } 22397c478bd9Sstevel@tonic-gate if (listen(sock, 30) < 0) { 22407c478bd9Sstevel@tonic-gate logperror("main: listen"); 22417c478bd9Sstevel@tonic-gate exit(1); 22427c478bd9Sstevel@tonic-gate } 22437c478bd9Sstevel@tonic-gate if (poll_add(sock) == -1) { 22447c478bd9Sstevel@tonic-gate (void) close(sock); 22457c478bd9Sstevel@tonic-gate exit(1); 22467c478bd9Sstevel@tonic-gate } 22477c478bd9Sstevel@tonic-gate 22487c478bd9Sstevel@tonic-gate return (sock); 22497c478bd9Sstevel@tonic-gate } 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate /* 22527c478bd9Sstevel@tonic-gate * Table of commands and their expected size; used by loopback_cmd(). 22537c478bd9Sstevel@tonic-gate */ 22547c478bd9Sstevel@tonic-gate static struct { 22557c478bd9Sstevel@tonic-gate const char *name; 22567c478bd9Sstevel@tonic-gate unsigned int size; 22577c478bd9Sstevel@tonic-gate } commands[] = { 22587c478bd9Sstevel@tonic-gate { "MI_PING", sizeof (uint32_t) }, 22597c478bd9Sstevel@tonic-gate { "MI_OFFLINE", sizeof (mi_offline_t) }, 22607c478bd9Sstevel@tonic-gate { "MI_UNDO_OFFLINE", sizeof (mi_undo_offline_t) }, 22617c478bd9Sstevel@tonic-gate { "MI_QUERY", sizeof (mi_query_t) } 22627c478bd9Sstevel@tonic-gate }; 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate /* 2265e11c3f44Smeem * Commands received over the loopback interface come here (via libipmp). 22667c478bd9Sstevel@tonic-gate */ 22677c478bd9Sstevel@tonic-gate static void 22687c478bd9Sstevel@tonic-gate loopback_cmd(int sock, int family) 22697c478bd9Sstevel@tonic-gate { 22707c478bd9Sstevel@tonic-gate int newfd; 22717c478bd9Sstevel@tonic-gate ssize_t len; 2272e11c3f44Smeem boolean_t is_priv = _B_FALSE; 22737c478bd9Sstevel@tonic-gate struct sockaddr_storage peer; 22747c478bd9Sstevel@tonic-gate struct sockaddr_in *peer_sin; 22757c478bd9Sstevel@tonic-gate struct sockaddr_in6 *peer_sin6; 22767c478bd9Sstevel@tonic-gate socklen_t peerlen; 22777c478bd9Sstevel@tonic-gate union mi_commands mpi; 22787c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 22797c478bd9Sstevel@tonic-gate uint_t cmd; 22807c478bd9Sstevel@tonic-gate int retval; 22817c478bd9Sstevel@tonic-gate 22827c478bd9Sstevel@tonic-gate peerlen = sizeof (peer); 22837c478bd9Sstevel@tonic-gate newfd = accept(sock, (struct sockaddr *)&peer, &peerlen); 22847c478bd9Sstevel@tonic-gate if (newfd < 0) { 22857c478bd9Sstevel@tonic-gate logperror("loopback_cmd: accept"); 22867c478bd9Sstevel@tonic-gate return; 22877c478bd9Sstevel@tonic-gate } 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate switch (family) { 22907c478bd9Sstevel@tonic-gate case AF_INET: 22917c478bd9Sstevel@tonic-gate /* 22927c478bd9Sstevel@tonic-gate * Validate the address and port to make sure that 22937c478bd9Sstevel@tonic-gate * non privileged processes don't connect and start 22947c478bd9Sstevel@tonic-gate * talking to us. 22957c478bd9Sstevel@tonic-gate */ 22967c478bd9Sstevel@tonic-gate if (peerlen != sizeof (struct sockaddr_in)) { 22977c478bd9Sstevel@tonic-gate logerr("loopback_cmd: AF_INET peerlen %d\n", peerlen); 22987c478bd9Sstevel@tonic-gate (void) close(newfd); 22997c478bd9Sstevel@tonic-gate return; 23007c478bd9Sstevel@tonic-gate } 23017c478bd9Sstevel@tonic-gate peer_sin = (struct sockaddr_in *)&peer; 2302e11c3f44Smeem is_priv = ntohs(peer_sin->sin_port) < IPPORT_RESERVED; 23037c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET, &peer_sin->sin_addr.s_addr, 23047c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 2305e11c3f44Smeem 2306e11c3f44Smeem if (ntohl(peer_sin->sin_addr.s_addr) != INADDR_LOOPBACK) { 23077c478bd9Sstevel@tonic-gate logerr("Attempt to connect from addr %s port %d\n", 23087c478bd9Sstevel@tonic-gate abuf, ntohs(peer_sin->sin_port)); 23097c478bd9Sstevel@tonic-gate (void) close(newfd); 23107c478bd9Sstevel@tonic-gate return; 23117c478bd9Sstevel@tonic-gate } 23127c478bd9Sstevel@tonic-gate break; 23137c478bd9Sstevel@tonic-gate 23147c478bd9Sstevel@tonic-gate case AF_INET6: 23157c478bd9Sstevel@tonic-gate if (peerlen != sizeof (struct sockaddr_in6)) { 23167c478bd9Sstevel@tonic-gate logerr("loopback_cmd: AF_INET6 peerlen %d\n", peerlen); 23177c478bd9Sstevel@tonic-gate (void) close(newfd); 23187c478bd9Sstevel@tonic-gate return; 23197c478bd9Sstevel@tonic-gate } 23207c478bd9Sstevel@tonic-gate /* 23217c478bd9Sstevel@tonic-gate * Validate the address and port to make sure that 23227c478bd9Sstevel@tonic-gate * non privileged processes don't connect and start 23237c478bd9Sstevel@tonic-gate * talking to us. 23247c478bd9Sstevel@tonic-gate */ 23257c478bd9Sstevel@tonic-gate peer_sin6 = (struct sockaddr_in6 *)&peer; 2326e11c3f44Smeem is_priv = ntohs(peer_sin6->sin6_port) < IPPORT_RESERVED; 23277c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, &peer_sin6->sin6_addr, abuf, 23287c478bd9Sstevel@tonic-gate sizeof (abuf)); 2329e11c3f44Smeem if (!IN6_IS_ADDR_LOOPBACK(&peer_sin6->sin6_addr)) { 23307c478bd9Sstevel@tonic-gate logerr("Attempt to connect from addr %s port %d\n", 23317c478bd9Sstevel@tonic-gate abuf, ntohs(peer_sin6->sin6_port)); 23327c478bd9Sstevel@tonic-gate (void) close(newfd); 23337c478bd9Sstevel@tonic-gate return; 23347c478bd9Sstevel@tonic-gate } 23357c478bd9Sstevel@tonic-gate 23367c478bd9Sstevel@tonic-gate default: 23377c478bd9Sstevel@tonic-gate logdebug("loopback_cmd: family %d\n", family); 23387c478bd9Sstevel@tonic-gate (void) close(newfd); 23397c478bd9Sstevel@tonic-gate return; 23407c478bd9Sstevel@tonic-gate } 23417c478bd9Sstevel@tonic-gate 23427c478bd9Sstevel@tonic-gate /* 23437c478bd9Sstevel@tonic-gate * The sizeof the 'mpi' buffer corresponds to the maximum size of 23447c478bd9Sstevel@tonic-gate * all supported commands 23457c478bd9Sstevel@tonic-gate */ 23467c478bd9Sstevel@tonic-gate len = read(newfd, &mpi, sizeof (mpi)); 23477c478bd9Sstevel@tonic-gate 23487c478bd9Sstevel@tonic-gate /* 23497c478bd9Sstevel@tonic-gate * In theory, we can receive any sized message for a stream socket, 23507c478bd9Sstevel@tonic-gate * but we don't expect that to happen for a small message over a 23517c478bd9Sstevel@tonic-gate * loopback connection. 23527c478bd9Sstevel@tonic-gate */ 23537c478bd9Sstevel@tonic-gate if (len < sizeof (uint32_t)) { 23547c478bd9Sstevel@tonic-gate logerr("loopback_cmd: bad command format or read returns " 23557c478bd9Sstevel@tonic-gate "partial data %d\n", len); 2356e11c3f44Smeem (void) close(newfd); 2357e11c3f44Smeem return; 23587c478bd9Sstevel@tonic-gate } 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate cmd = mpi.mi_command; 23617c478bd9Sstevel@tonic-gate if (cmd >= MI_NCMD) { 23627c478bd9Sstevel@tonic-gate logerr("loopback_cmd: unknown command id `%d'\n", cmd); 23637c478bd9Sstevel@tonic-gate (void) close(newfd); 23647c478bd9Sstevel@tonic-gate return; 23657c478bd9Sstevel@tonic-gate } 23667c478bd9Sstevel@tonic-gate 2367e11c3f44Smeem /* 2368e11c3f44Smeem * Only MI_PING and MI_QUERY can come from unprivileged sources. 2369e11c3f44Smeem */ 2370e11c3f44Smeem if (!is_priv && (cmd != MI_QUERY && cmd != MI_PING)) { 2371e11c3f44Smeem logerr("Unprivileged request from %s for privileged " 2372e11c3f44Smeem "command %s\n", abuf, commands[cmd].name); 2373e11c3f44Smeem (void) close(newfd); 2374e11c3f44Smeem return; 2375e11c3f44Smeem } 2376e11c3f44Smeem 23777c478bd9Sstevel@tonic-gate if (len < commands[cmd].size) { 23787c478bd9Sstevel@tonic-gate logerr("loopback_cmd: short %s command (expected %d, got %d)\n", 23797c478bd9Sstevel@tonic-gate commands[cmd].name, commands[cmd].size, len); 23807c478bd9Sstevel@tonic-gate (void) close(newfd); 23817c478bd9Sstevel@tonic-gate return; 23827c478bd9Sstevel@tonic-gate } 23837c478bd9Sstevel@tonic-gate 23847c478bd9Sstevel@tonic-gate retval = process_cmd(newfd, &mpi); 23857c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) { 23867c478bd9Sstevel@tonic-gate logerr("failed processing %s: %s\n", commands[cmd].name, 23877c478bd9Sstevel@tonic-gate ipmp_errmsg(retval)); 23887c478bd9Sstevel@tonic-gate } 23897c478bd9Sstevel@tonic-gate (void) close(newfd); 23907c478bd9Sstevel@tonic-gate } 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate /* 2393e11c3f44Smeem * Process the commands received via libipmp. 23947c478bd9Sstevel@tonic-gate */ 23957c478bd9Sstevel@tonic-gate static unsigned int 23967c478bd9Sstevel@tonic-gate process_cmd(int newfd, union mi_commands *mpi) 23977c478bd9Sstevel@tonic-gate { 23987c478bd9Sstevel@tonic-gate struct phyint *pi; 23997c478bd9Sstevel@tonic-gate struct mi_offline *mio; 24007c478bd9Sstevel@tonic-gate struct mi_undo_offline *miu; 2401e11c3f44Smeem unsigned int retval; 24027c478bd9Sstevel@tonic-gate 2403e11c3f44Smeem switch (mpi->mi_command) { 2404e11c3f44Smeem case MI_PING: 2405e11c3f44Smeem return (send_result(newfd, IPMP_SUCCESS, 0)); 24067c478bd9Sstevel@tonic-gate 24077c478bd9Sstevel@tonic-gate case MI_OFFLINE: 24087c478bd9Sstevel@tonic-gate mio = &mpi->mi_ocmd; 2409e11c3f44Smeem 24107c478bd9Sstevel@tonic-gate pi = phyint_lookup(mio->mio_ifname); 24117c478bd9Sstevel@tonic-gate if (pi == NULL) 2412e11c3f44Smeem return (send_result(newfd, IPMP_EUNKIF, 0)); 24137c478bd9Sstevel@tonic-gate 2414e11c3f44Smeem retval = phyint_offline(pi, mio->mio_min_redundancy); 2415e11c3f44Smeem if (retval == IPMP_FAILURE) 24167c478bd9Sstevel@tonic-gate return (send_result(newfd, IPMP_FAILURE, errno)); 24177c478bd9Sstevel@tonic-gate 2418e11c3f44Smeem return (send_result(newfd, retval, 0)); 24197c478bd9Sstevel@tonic-gate 24207c478bd9Sstevel@tonic-gate case MI_UNDO_OFFLINE: 24217c478bd9Sstevel@tonic-gate miu = &mpi->mi_ucmd; 2422e11c3f44Smeem 24237c478bd9Sstevel@tonic-gate pi = phyint_lookup(miu->miu_ifname); 2424e11c3f44Smeem if (pi == NULL) 2425e11c3f44Smeem return (send_result(newfd, IPMP_EUNKIF, 0)); 24267c478bd9Sstevel@tonic-gate 2427e11c3f44Smeem retval = phyint_undo_offline(pi); 2428e11c3f44Smeem if (retval == IPMP_FAILURE) 24297c478bd9Sstevel@tonic-gate return (send_result(newfd, IPMP_FAILURE, errno)); 24307c478bd9Sstevel@tonic-gate 2431e11c3f44Smeem return (send_result(newfd, retval, 0)); 24327c478bd9Sstevel@tonic-gate 24337c478bd9Sstevel@tonic-gate case MI_QUERY: 24347c478bd9Sstevel@tonic-gate return (process_query(newfd, &mpi->mi_qcmd)); 24357c478bd9Sstevel@tonic-gate 24367c478bd9Sstevel@tonic-gate default: 24377c478bd9Sstevel@tonic-gate break; 24387c478bd9Sstevel@tonic-gate } 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate return (send_result(newfd, IPMP_EPROTO, 0)); 24417c478bd9Sstevel@tonic-gate } 24427c478bd9Sstevel@tonic-gate 24437c478bd9Sstevel@tonic-gate /* 24447c478bd9Sstevel@tonic-gate * Process the query request pointed to by `miq' and send a reply on file 24457c478bd9Sstevel@tonic-gate * descriptor `fd'. Returns an IPMP error code. 24467c478bd9Sstevel@tonic-gate */ 24477c478bd9Sstevel@tonic-gate static unsigned int 24487c478bd9Sstevel@tonic-gate process_query(int fd, mi_query_t *miq) 24497c478bd9Sstevel@tonic-gate { 2450e11c3f44Smeem ipmp_addrinfo_t *adinfop; 2451e11c3f44Smeem ipmp_addrinfolist_t *adlp; 24527c478bd9Sstevel@tonic-gate ipmp_groupinfo_t *grinfop; 24537c478bd9Sstevel@tonic-gate ipmp_groupinfolist_t *grlp; 24547c478bd9Sstevel@tonic-gate ipmp_grouplist_t *grlistp; 24557c478bd9Sstevel@tonic-gate ipmp_ifinfo_t *ifinfop; 24567c478bd9Sstevel@tonic-gate ipmp_ifinfolist_t *iflp; 24577c478bd9Sstevel@tonic-gate ipmp_snap_t *snap; 24587c478bd9Sstevel@tonic-gate unsigned int retval; 24597c478bd9Sstevel@tonic-gate 24607c478bd9Sstevel@tonic-gate switch (miq->miq_inforeq) { 2461e11c3f44Smeem case IPMP_ADDRINFO: 2462e11c3f44Smeem retval = getgraddrinfo(miq->miq_grname, &miq->miq_addr, 2463e11c3f44Smeem &adinfop); 2464e11c3f44Smeem if (retval != IPMP_SUCCESS) 2465e11c3f44Smeem return (send_result(fd, retval, errno)); 2466e11c3f44Smeem 2467e11c3f44Smeem retval = send_result(fd, IPMP_SUCCESS, 0); 2468e11c3f44Smeem if (retval == IPMP_SUCCESS) 2469e11c3f44Smeem retval = send_addrinfo(fd, adinfop); 2470e11c3f44Smeem 2471e11c3f44Smeem ipmp_freeaddrinfo(adinfop); 2472e11c3f44Smeem return (retval); 2473e11c3f44Smeem 24747c478bd9Sstevel@tonic-gate case IPMP_GROUPLIST: 24757c478bd9Sstevel@tonic-gate retval = getgrouplist(&grlistp); 24767c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 24777c478bd9Sstevel@tonic-gate return (send_result(fd, retval, errno)); 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate retval = send_result(fd, IPMP_SUCCESS, 0); 24807c478bd9Sstevel@tonic-gate if (retval == IPMP_SUCCESS) 24817c478bd9Sstevel@tonic-gate retval = send_grouplist(fd, grlistp); 24827c478bd9Sstevel@tonic-gate 24837c478bd9Sstevel@tonic-gate ipmp_freegrouplist(grlistp); 24847c478bd9Sstevel@tonic-gate return (retval); 24857c478bd9Sstevel@tonic-gate 24867c478bd9Sstevel@tonic-gate case IPMP_GROUPINFO: 24877c478bd9Sstevel@tonic-gate miq->miq_grname[LIFGRNAMSIZ - 1] = '\0'; 2488e11c3f44Smeem retval = getgroupinfo(miq->miq_grname, &grinfop); 24897c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 24907c478bd9Sstevel@tonic-gate return (send_result(fd, retval, errno)); 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate retval = send_result(fd, IPMP_SUCCESS, 0); 24937c478bd9Sstevel@tonic-gate if (retval == IPMP_SUCCESS) 24947c478bd9Sstevel@tonic-gate retval = send_groupinfo(fd, grinfop); 24957c478bd9Sstevel@tonic-gate 24967c478bd9Sstevel@tonic-gate ipmp_freegroupinfo(grinfop); 24977c478bd9Sstevel@tonic-gate return (retval); 24987c478bd9Sstevel@tonic-gate 24997c478bd9Sstevel@tonic-gate case IPMP_IFINFO: 25007c478bd9Sstevel@tonic-gate miq->miq_ifname[LIFNAMSIZ - 1] = '\0'; 25017c478bd9Sstevel@tonic-gate retval = getifinfo(miq->miq_ifname, &ifinfop); 25027c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25037c478bd9Sstevel@tonic-gate return (send_result(fd, retval, errno)); 25047c478bd9Sstevel@tonic-gate 25057c478bd9Sstevel@tonic-gate retval = send_result(fd, IPMP_SUCCESS, 0); 25067c478bd9Sstevel@tonic-gate if (retval == IPMP_SUCCESS) 25077c478bd9Sstevel@tonic-gate retval = send_ifinfo(fd, ifinfop); 25087c478bd9Sstevel@tonic-gate 25097c478bd9Sstevel@tonic-gate ipmp_freeifinfo(ifinfop); 25107c478bd9Sstevel@tonic-gate return (retval); 25117c478bd9Sstevel@tonic-gate 25127c478bd9Sstevel@tonic-gate case IPMP_SNAP: 2513e11c3f44Smeem /* 2514e11c3f44Smeem * Before taking the snapshot, sync with the kernel. 2515e11c3f44Smeem */ 2516e11c3f44Smeem initifs(); 2517e11c3f44Smeem 25187c478bd9Sstevel@tonic-gate retval = getsnap(&snap); 25197c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25207c478bd9Sstevel@tonic-gate return (send_result(fd, retval, errno)); 25217c478bd9Sstevel@tonic-gate 25227c478bd9Sstevel@tonic-gate retval = send_result(fd, IPMP_SUCCESS, 0); 25237c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25247c478bd9Sstevel@tonic-gate goto out; 25257c478bd9Sstevel@tonic-gate 25267c478bd9Sstevel@tonic-gate retval = ipmp_writetlv(fd, IPMP_SNAP, sizeof (*snap), snap); 25277c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25287c478bd9Sstevel@tonic-gate goto out; 25297c478bd9Sstevel@tonic-gate 25307c478bd9Sstevel@tonic-gate retval = send_grouplist(fd, snap->sn_grlistp); 25317c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25327c478bd9Sstevel@tonic-gate goto out; 25337c478bd9Sstevel@tonic-gate 25347c478bd9Sstevel@tonic-gate iflp = snap->sn_ifinfolistp; 25357c478bd9Sstevel@tonic-gate for (; iflp != NULL; iflp = iflp->ifl_next) { 25367c478bd9Sstevel@tonic-gate retval = send_ifinfo(fd, iflp->ifl_ifinfop); 25377c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25387c478bd9Sstevel@tonic-gate goto out; 25397c478bd9Sstevel@tonic-gate } 25407c478bd9Sstevel@tonic-gate 25417c478bd9Sstevel@tonic-gate grlp = snap->sn_grinfolistp; 25427c478bd9Sstevel@tonic-gate for (; grlp != NULL; grlp = grlp->grl_next) { 25437c478bd9Sstevel@tonic-gate retval = send_groupinfo(fd, grlp->grl_grinfop); 25447c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25457c478bd9Sstevel@tonic-gate goto out; 25467c478bd9Sstevel@tonic-gate } 2547e11c3f44Smeem 2548e11c3f44Smeem adlp = snap->sn_adinfolistp; 2549e11c3f44Smeem for (; adlp != NULL; adlp = adlp->adl_next) { 2550e11c3f44Smeem retval = send_addrinfo(fd, adlp->adl_adinfop); 2551e11c3f44Smeem if (retval != IPMP_SUCCESS) 2552e11c3f44Smeem goto out; 2553e11c3f44Smeem } 25547c478bd9Sstevel@tonic-gate out: 25557c478bd9Sstevel@tonic-gate ipmp_snap_free(snap); 25567c478bd9Sstevel@tonic-gate return (retval); 25577c478bd9Sstevel@tonic-gate 25587c478bd9Sstevel@tonic-gate default: 25597c478bd9Sstevel@tonic-gate break; 25607c478bd9Sstevel@tonic-gate 25617c478bd9Sstevel@tonic-gate } 25627c478bd9Sstevel@tonic-gate return (send_result(fd, IPMP_EPROTO, 0)); 25637c478bd9Sstevel@tonic-gate } 25647c478bd9Sstevel@tonic-gate 25657c478bd9Sstevel@tonic-gate /* 25667c478bd9Sstevel@tonic-gate * Send the group information pointed to by `grinfop' on file descriptor `fd'. 25677c478bd9Sstevel@tonic-gate * Returns an IPMP error code. 25687c478bd9Sstevel@tonic-gate */ 25697c478bd9Sstevel@tonic-gate static unsigned int 25707c478bd9Sstevel@tonic-gate send_groupinfo(int fd, ipmp_groupinfo_t *grinfop) 25717c478bd9Sstevel@tonic-gate { 25727c478bd9Sstevel@tonic-gate ipmp_iflist_t *iflistp = grinfop->gr_iflistp; 2573e11c3f44Smeem ipmp_addrlist_t *adlistp = grinfop->gr_adlistp; 25747c478bd9Sstevel@tonic-gate unsigned int retval; 25757c478bd9Sstevel@tonic-gate 25767c478bd9Sstevel@tonic-gate retval = ipmp_writetlv(fd, IPMP_GROUPINFO, sizeof (*grinfop), grinfop); 25777c478bd9Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25787c478bd9Sstevel@tonic-gate return (retval); 25797c478bd9Sstevel@tonic-gate 2580e11c3f44Smeem retval = ipmp_writetlv(fd, IPMP_IFLIST, 2581e11c3f44Smeem IPMP_IFLIST_SIZE(iflistp->il_nif), iflistp); 2582e11c3f44Smeem if (retval != IPMP_SUCCESS) 2583e11c3f44Smeem return (retval); 2584e11c3f44Smeem 2585e11c3f44Smeem return (ipmp_writetlv(fd, IPMP_ADDRLIST, 2586e11c3f44Smeem IPMP_ADDRLIST_SIZE(adlistp->al_naddr), adlistp)); 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate /* 25907c478bd9Sstevel@tonic-gate * Send the interface information pointed to by `ifinfop' on file descriptor 25917c478bd9Sstevel@tonic-gate * `fd'. Returns an IPMP error code. 25927c478bd9Sstevel@tonic-gate */ 25937c478bd9Sstevel@tonic-gate static unsigned int 25947c478bd9Sstevel@tonic-gate send_ifinfo(int fd, ipmp_ifinfo_t *ifinfop) 25957c478bd9Sstevel@tonic-gate { 2596e11c3f44Smeem ipmp_addrlist_t *adlist4p = ifinfop->if_targinfo4.it_targlistp; 2597e11c3f44Smeem ipmp_addrlist_t *adlist6p = ifinfop->if_targinfo6.it_targlistp; 2598e11c3f44Smeem unsigned int retval; 2599e11c3f44Smeem 2600e11c3f44Smeem retval = ipmp_writetlv(fd, IPMP_IFINFO, sizeof (*ifinfop), ifinfop); 2601e11c3f44Smeem if (retval != IPMP_SUCCESS) 2602e11c3f44Smeem return (retval); 2603e11c3f44Smeem 2604e11c3f44Smeem retval = ipmp_writetlv(fd, IPMP_ADDRLIST, 2605e11c3f44Smeem IPMP_ADDRLIST_SIZE(adlist4p->al_naddr), adlist4p); 2606e11c3f44Smeem if (retval != IPMP_SUCCESS) 2607e11c3f44Smeem return (retval); 2608e11c3f44Smeem 2609e11c3f44Smeem return (ipmp_writetlv(fd, IPMP_ADDRLIST, 2610e11c3f44Smeem IPMP_ADDRLIST_SIZE(adlist6p->al_naddr), adlist6p)); 2611e11c3f44Smeem } 2612e11c3f44Smeem 2613e11c3f44Smeem /* 2614e11c3f44Smeem * Send the address information pointed to by `adinfop' on file descriptor 2615e11c3f44Smeem * `fd'. Returns an IPMP error code. 2616e11c3f44Smeem */ 2617e11c3f44Smeem static unsigned int 2618e11c3f44Smeem send_addrinfo(int fd, ipmp_addrinfo_t *adinfop) 2619e11c3f44Smeem { 2620e11c3f44Smeem return (ipmp_writetlv(fd, IPMP_ADDRINFO, sizeof (*adinfop), adinfop)); 26217c478bd9Sstevel@tonic-gate } 26227c478bd9Sstevel@tonic-gate 26237c478bd9Sstevel@tonic-gate /* 26247c478bd9Sstevel@tonic-gate * Send the group list pointed to by `grlistp' on file descriptor `fd'. 26257c478bd9Sstevel@tonic-gate * Returns an IPMP error code. 26267c478bd9Sstevel@tonic-gate */ 26277c478bd9Sstevel@tonic-gate static unsigned int 26287c478bd9Sstevel@tonic-gate send_grouplist(int fd, ipmp_grouplist_t *grlistp) 26297c478bd9Sstevel@tonic-gate { 26307c478bd9Sstevel@tonic-gate return (ipmp_writetlv(fd, IPMP_GROUPLIST, 26317c478bd9Sstevel@tonic-gate IPMP_GROUPLIST_SIZE(grlistp->gl_ngroup), grlistp)); 26327c478bd9Sstevel@tonic-gate } 26337c478bd9Sstevel@tonic-gate 26347c478bd9Sstevel@tonic-gate /* 26357c478bd9Sstevel@tonic-gate * Initialize an mi_result_t structure using `error' and `syserror' and 26367c478bd9Sstevel@tonic-gate * send it on file descriptor `fd'. Returns an IPMP error code. 26377c478bd9Sstevel@tonic-gate */ 26387c478bd9Sstevel@tonic-gate static unsigned int 26397c478bd9Sstevel@tonic-gate send_result(int fd, unsigned int error, int syserror) 26407c478bd9Sstevel@tonic-gate { 26417c478bd9Sstevel@tonic-gate mi_result_t me; 26427c478bd9Sstevel@tonic-gate 26437c478bd9Sstevel@tonic-gate me.me_mpathd_error = error; 26447c478bd9Sstevel@tonic-gate if (error == IPMP_FAILURE) 26457c478bd9Sstevel@tonic-gate me.me_sys_error = syserror; 26467c478bd9Sstevel@tonic-gate else 26477c478bd9Sstevel@tonic-gate me.me_sys_error = 0; 26487c478bd9Sstevel@tonic-gate 26497c478bd9Sstevel@tonic-gate return (ipmp_write(fd, &me, sizeof (me))); 26507c478bd9Sstevel@tonic-gate } 26517c478bd9Sstevel@tonic-gate 26527c478bd9Sstevel@tonic-gate /* 26537c478bd9Sstevel@tonic-gate * Daemonize the process. 26547c478bd9Sstevel@tonic-gate */ 26557c478bd9Sstevel@tonic-gate static boolean_t 26567c478bd9Sstevel@tonic-gate daemonize(void) 26577c478bd9Sstevel@tonic-gate { 26587c478bd9Sstevel@tonic-gate switch (fork()) { 26597c478bd9Sstevel@tonic-gate case -1: 26607c478bd9Sstevel@tonic-gate return (_B_FALSE); 26617c478bd9Sstevel@tonic-gate 26627c478bd9Sstevel@tonic-gate case 0: 26637c478bd9Sstevel@tonic-gate /* 26647c478bd9Sstevel@tonic-gate * Lose our controlling terminal, and become both a session 26657c478bd9Sstevel@tonic-gate * leader and a process group leader. 26667c478bd9Sstevel@tonic-gate */ 26677c478bd9Sstevel@tonic-gate if (setsid() == -1) 26687c478bd9Sstevel@tonic-gate return (_B_FALSE); 26697c478bd9Sstevel@tonic-gate 26707c478bd9Sstevel@tonic-gate /* 26717c478bd9Sstevel@tonic-gate * Under POSIX, a session leader can accidentally (through 26727c478bd9Sstevel@tonic-gate * open(2)) acquire a controlling terminal if it does not 26737c478bd9Sstevel@tonic-gate * have one. Just to be safe, fork() again so we are not a 26747c478bd9Sstevel@tonic-gate * session leader. 26757c478bd9Sstevel@tonic-gate */ 26767c478bd9Sstevel@tonic-gate switch (fork()) { 26777c478bd9Sstevel@tonic-gate case -1: 26787c478bd9Sstevel@tonic-gate return (_B_FALSE); 26797c478bd9Sstevel@tonic-gate 26807c478bd9Sstevel@tonic-gate case 0: 26817c478bd9Sstevel@tonic-gate (void) chdir("/"); 26827c478bd9Sstevel@tonic-gate (void) umask(022); 26837c478bd9Sstevel@tonic-gate (void) fdwalk(closefunc, NULL); 26847c478bd9Sstevel@tonic-gate break; 26857c478bd9Sstevel@tonic-gate 26867c478bd9Sstevel@tonic-gate default: 26877c478bd9Sstevel@tonic-gate _exit(EXIT_SUCCESS); 26887c478bd9Sstevel@tonic-gate } 26897c478bd9Sstevel@tonic-gate break; 26907c478bd9Sstevel@tonic-gate 26917c478bd9Sstevel@tonic-gate default: 26927c478bd9Sstevel@tonic-gate _exit(EXIT_SUCCESS); 26937c478bd9Sstevel@tonic-gate } 26947c478bd9Sstevel@tonic-gate 26957c478bd9Sstevel@tonic-gate return (_B_TRUE); 26967c478bd9Sstevel@tonic-gate } 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate /* 26997c478bd9Sstevel@tonic-gate * The parent has created some fds before forking on purpose, keep them open. 27007c478bd9Sstevel@tonic-gate */ 27017c478bd9Sstevel@tonic-gate static int 27027c478bd9Sstevel@tonic-gate closefunc(void *not_used, int fd) 27037c478bd9Sstevel@tonic-gate /* ARGSUSED */ 27047c478bd9Sstevel@tonic-gate { 27057c478bd9Sstevel@tonic-gate if (fd != lsock_v4 && fd != lsock_v6) 27067c478bd9Sstevel@tonic-gate (void) close(fd); 27077c478bd9Sstevel@tonic-gate return (0); 27087c478bd9Sstevel@tonic-gate } 27097c478bd9Sstevel@tonic-gate 27107c478bd9Sstevel@tonic-gate /* LOGGER */ 27117c478bd9Sstevel@tonic-gate 27127c478bd9Sstevel@tonic-gate #include <syslog.h> 27137c478bd9Sstevel@tonic-gate 27147c478bd9Sstevel@tonic-gate /* 27157c478bd9Sstevel@tonic-gate * Logging routines. All routines log to syslog, unless the daemon is 27167c478bd9Sstevel@tonic-gate * running in the foreground, in which case the logging goes to stderr. 27177c478bd9Sstevel@tonic-gate * 27187c478bd9Sstevel@tonic-gate * The following routines are available: 27197c478bd9Sstevel@tonic-gate * 27207c478bd9Sstevel@tonic-gate * logdebug(): A printf-like function for outputting debug messages 27217c478bd9Sstevel@tonic-gate * (messages at LOG_DEBUG) that are only of use to developers. 27227c478bd9Sstevel@tonic-gate * 27237c478bd9Sstevel@tonic-gate * logtrace(): A printf-like function for outputting tracing messages 27247c478bd9Sstevel@tonic-gate * (messages at LOG_INFO) from the daemon. This is typically used 27257c478bd9Sstevel@tonic-gate * to log the receipt of interesting network-related conditions. 27267c478bd9Sstevel@tonic-gate * 27277c478bd9Sstevel@tonic-gate * logerr(): A printf-like function for outputting error messages 27287c478bd9Sstevel@tonic-gate * (messages at LOG_ERR) from the daemon. 27297c478bd9Sstevel@tonic-gate * 27307c478bd9Sstevel@tonic-gate * logperror*(): A set of functions used to output error messages 27317c478bd9Sstevel@tonic-gate * (messages at LOG_ERR); these automatically append strerror(errno) 27327c478bd9Sstevel@tonic-gate * and a newline to the message passed to them. 27337c478bd9Sstevel@tonic-gate * 27347c478bd9Sstevel@tonic-gate * NOTE: since the logging functions write to syslog, the messages passed 27357c478bd9Sstevel@tonic-gate * to them are not eligible for localization. Thus, gettext() must 27367c478bd9Sstevel@tonic-gate * *not* be used. 27377c478bd9Sstevel@tonic-gate */ 27387c478bd9Sstevel@tonic-gate 27397c478bd9Sstevel@tonic-gate static int logging = 0; 27407c478bd9Sstevel@tonic-gate 27417c478bd9Sstevel@tonic-gate static void 27427c478bd9Sstevel@tonic-gate initlog(void) 27437c478bd9Sstevel@tonic-gate { 27447c478bd9Sstevel@tonic-gate logging++; 2745e3e7cd29Smeem openlog("in.mpathd", LOG_PID, LOG_DAEMON); 27467c478bd9Sstevel@tonic-gate } 27477c478bd9Sstevel@tonic-gate 2748e3e7cd29Smeem /* PRINTFLIKE2 */ 27497c478bd9Sstevel@tonic-gate void 2750e3e7cd29Smeem logmsg(int pri, const char *fmt, ...) 27517c478bd9Sstevel@tonic-gate { 27527c478bd9Sstevel@tonic-gate va_list ap; 27537c478bd9Sstevel@tonic-gate 27547c478bd9Sstevel@tonic-gate va_start(ap, fmt); 27557c478bd9Sstevel@tonic-gate 27567c478bd9Sstevel@tonic-gate if (logging) 2757e3e7cd29Smeem vsyslog(pri, fmt, ap); 27587c478bd9Sstevel@tonic-gate else 27597c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 27607c478bd9Sstevel@tonic-gate va_end(ap); 27617c478bd9Sstevel@tonic-gate } 27627c478bd9Sstevel@tonic-gate 27637c478bd9Sstevel@tonic-gate /* PRINTFLIKE1 */ 27647c478bd9Sstevel@tonic-gate void 2765e3e7cd29Smeem logperror(const char *str) 27667c478bd9Sstevel@tonic-gate { 27677c478bd9Sstevel@tonic-gate if (logging) 27687c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s: %m\n", str); 27697c478bd9Sstevel@tonic-gate else 27707c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); 27717c478bd9Sstevel@tonic-gate } 27727c478bd9Sstevel@tonic-gate 27737c478bd9Sstevel@tonic-gate void 2774e3e7cd29Smeem logperror_pii(struct phyint_instance *pii, const char *str) 27757c478bd9Sstevel@tonic-gate { 27767c478bd9Sstevel@tonic-gate if (logging) { 27777c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s (%s %s): %m\n", 27787c478bd9Sstevel@tonic-gate str, AF_STR(pii->pii_af), pii->pii_phyint->pi_name); 27797c478bd9Sstevel@tonic-gate } else { 27807c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s (%s %s): %s\n", 27817c478bd9Sstevel@tonic-gate str, AF_STR(pii->pii_af), pii->pii_phyint->pi_name, 27827c478bd9Sstevel@tonic-gate strerror(errno)); 27837c478bd9Sstevel@tonic-gate } 27847c478bd9Sstevel@tonic-gate } 27857c478bd9Sstevel@tonic-gate 27867c478bd9Sstevel@tonic-gate void 2787e3e7cd29Smeem logperror_li(struct logint *li, const char *str) 27887c478bd9Sstevel@tonic-gate { 27897c478bd9Sstevel@tonic-gate struct phyint_instance *pii = li->li_phyint_inst; 27907c478bd9Sstevel@tonic-gate 27917c478bd9Sstevel@tonic-gate if (logging) { 27927c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "%s (%s %s): %m\n", 27937c478bd9Sstevel@tonic-gate str, AF_STR(pii->pii_af), li->li_name); 27947c478bd9Sstevel@tonic-gate } else { 27957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s (%s %s): %s\n", 27967c478bd9Sstevel@tonic-gate str, AF_STR(pii->pii_af), li->li_name, 27977c478bd9Sstevel@tonic-gate strerror(errno)); 27987c478bd9Sstevel@tonic-gate } 27997c478bd9Sstevel@tonic-gate } 28007c478bd9Sstevel@tonic-gate 28017c478bd9Sstevel@tonic-gate void 28027c478bd9Sstevel@tonic-gate close_probe_socket(struct phyint_instance *pii, boolean_t polled) 28037c478bd9Sstevel@tonic-gate { 28047c478bd9Sstevel@tonic-gate if (polled) 28057c478bd9Sstevel@tonic-gate (void) poll_remove(pii->pii_probe_sock); 28067c478bd9Sstevel@tonic-gate (void) close(pii->pii_probe_sock); 28077c478bd9Sstevel@tonic-gate pii->pii_probe_sock = -1; 28087c478bd9Sstevel@tonic-gate pii->pii_basetime_inited = 0; 28097c478bd9Sstevel@tonic-gate } 2810e11c3f44Smeem 2811e11c3f44Smeem boolean_t 2812e11c3f44Smeem addrlist_add(addrlist_t **addrsp, const char *name, uint64_t flags, 2813e11c3f44Smeem struct sockaddr_storage *ssp) 2814e11c3f44Smeem { 2815e11c3f44Smeem addrlist_t *addrp; 2816e11c3f44Smeem 2817e11c3f44Smeem if ((addrp = malloc(sizeof (addrlist_t))) == NULL) 2818e11c3f44Smeem return (_B_FALSE); 2819e11c3f44Smeem 2820e11c3f44Smeem (void) strlcpy(addrp->al_name, name, LIFNAMSIZ); 2821e11c3f44Smeem addrp->al_flags = flags; 2822e11c3f44Smeem addrp->al_addr = *ssp; 2823e11c3f44Smeem addrp->al_next = *addrsp; 2824e11c3f44Smeem *addrsp = addrp; 2825e11c3f44Smeem return (_B_TRUE); 2826e11c3f44Smeem } 2827e11c3f44Smeem 2828e11c3f44Smeem void 2829e11c3f44Smeem addrlist_free(addrlist_t **addrsp) 2830e11c3f44Smeem { 2831e11c3f44Smeem addrlist_t *addrp, *next_addrp; 2832e11c3f44Smeem 2833e11c3f44Smeem for (addrp = *addrsp; addrp != NULL; addrp = next_addrp) { 2834e11c3f44Smeem next_addrp = addrp->al_next; 2835e11c3f44Smeem free(addrp); 2836e11c3f44Smeem } 2837e11c3f44Smeem *addrsp = NULL; 2838e11c3f44Smeem } 283927438c18SJon Anderson 284027438c18SJon Anderson /* 284127438c18SJon Anderson * Send down a T_OPTMGMT_REQ to ip asking for all data in the various 284227438c18SJon Anderson * tables defined by mib2.h. Pass the table information returned to the 284327438c18SJon Anderson * supplied function. 284427438c18SJon Anderson */ 284527438c18SJon Anderson static int 284627438c18SJon Anderson mibwalk(void (*proc)(mib_item_t *)) 284727438c18SJon Anderson { 284827438c18SJon Anderson mib_item_t *head_item = NULL; 284927438c18SJon Anderson mib_item_t *last_item = NULL; 285027438c18SJon Anderson mib_item_t *tmp; 285127438c18SJon Anderson struct strbuf ctlbuf, databuf; 285227438c18SJon Anderson int flags; 285327438c18SJon Anderson int rval; 285427438c18SJon Anderson uintptr_t buf[512 / sizeof (uintptr_t)]; 285527438c18SJon Anderson struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 285627438c18SJon Anderson struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 285727438c18SJon Anderson struct T_error_ack *tea = (struct T_error_ack *)buf; 285827438c18SJon Anderson struct opthdr *req, *optp; 285927438c18SJon Anderson int status = -1; 286027438c18SJon Anderson 286127438c18SJon Anderson if (mibfd == -1) { 286227438c18SJon Anderson if ((mibfd = open("/dev/ip", O_RDWR)) < 0) { 286327438c18SJon Anderson logperror("mibwalk(): ip open"); 286427438c18SJon Anderson return (status); 286527438c18SJon Anderson } 286627438c18SJon Anderson } 286727438c18SJon Anderson 286827438c18SJon Anderson tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 286927438c18SJon Anderson tor->OPT_offset = sizeof (struct T_optmgmt_req); 287027438c18SJon Anderson tor->OPT_length = sizeof (struct opthdr); 287127438c18SJon Anderson tor->MGMT_flags = T_CURRENT; 287227438c18SJon Anderson 287327438c18SJon Anderson /* 287427438c18SJon Anderson * Note: we use the special level value below so that IP will return 287527438c18SJon Anderson * us information concerning IRE_MARK_TESTHIDDEN routes. 287627438c18SJon Anderson */ 287727438c18SJon Anderson req = (struct opthdr *)&tor[1]; 2878*bd670b35SErik Nordmark req->level = EXPER_IP_AND_ALL_IRES; 287927438c18SJon Anderson req->name = 0; 288027438c18SJon Anderson req->len = 0; 288127438c18SJon Anderson 288227438c18SJon Anderson ctlbuf.buf = (char *)&buf; 288327438c18SJon Anderson ctlbuf.len = tor->OPT_length + tor->OPT_offset; 288427438c18SJon Anderson 288527438c18SJon Anderson if (putmsg(mibfd, &ctlbuf, NULL, 0) == -1) { 288627438c18SJon Anderson logperror("mibwalk(): putmsg(ctl)"); 288727438c18SJon Anderson return (status); 288827438c18SJon Anderson } 288927438c18SJon Anderson 289027438c18SJon Anderson /* 289127438c18SJon Anderson * The response consists of multiple T_OPTMGMT_ACK msgs, 1 msg for 289227438c18SJon Anderson * each table defined in mib2.h. Each T_OPTMGMT_ACK msg contains 289327438c18SJon Anderson * a control and data part. The control part contains a struct 289427438c18SJon Anderson * T_optmgmt_ack followed by a struct opthdr. The 'opthdr' identifies 289527438c18SJon Anderson * the level, name and length of the data in the data part. The 289627438c18SJon Anderson * data part contains the actual table data. The last message 289727438c18SJon Anderson * is an end-of-data (EOD), consisting of a T_OPTMGMT_ACK and a 289827438c18SJon Anderson * single option with zero optlen. 289927438c18SJon Anderson */ 290027438c18SJon Anderson for (;;) { 290127438c18SJon Anderson errno = flags = 0; 290227438c18SJon Anderson ctlbuf.maxlen = sizeof (buf); 290327438c18SJon Anderson rval = getmsg(mibfd, &ctlbuf, NULL, &flags); 290427438c18SJon Anderson if (rval & MORECTL || rval < 0) { 290527438c18SJon Anderson if (errno == EINTR) 290627438c18SJon Anderson continue; 290727438c18SJon Anderson logerr("mibwalk(): getmsg(ctl) ret: %d err: %d\n", 290827438c18SJon Anderson rval, errno); 290927438c18SJon Anderson goto error; 291027438c18SJon Anderson } 291127438c18SJon Anderson if (ctlbuf.len < sizeof (t_scalar_t)) { 291227438c18SJon Anderson logerr("mibwalk(): ctlbuf.len %d\n", ctlbuf.len); 291327438c18SJon Anderson goto error; 291427438c18SJon Anderson } 291527438c18SJon Anderson 291627438c18SJon Anderson switch (toa->PRIM_type) { 291727438c18SJon Anderson case T_ERROR_ACK: 291827438c18SJon Anderson if (ctlbuf.len < sizeof (struct T_error_ack)) { 291927438c18SJon Anderson logerr("mibwalk(): T_ERROR_ACK ctlbuf " 292027438c18SJon Anderson "too short: %d\n", ctlbuf.len); 292127438c18SJon Anderson goto error; 292227438c18SJon Anderson } 292327438c18SJon Anderson logerr("mibwalk(): T_ERROR_ACK: TLI_err = 0x%lx: %s\n" 292427438c18SJon Anderson " UNIX_err = 0x%lx\n", tea->TLI_error, 292527438c18SJon Anderson t_strerror(tea->TLI_error), tea->UNIX_error); 292627438c18SJon Anderson goto error; 292727438c18SJon Anderson 292827438c18SJon Anderson case T_OPTMGMT_ACK: 292927438c18SJon Anderson optp = (struct opthdr *)&toa[1]; 293027438c18SJon Anderson if (ctlbuf.len < (sizeof (struct T_optmgmt_ack) + 293127438c18SJon Anderson sizeof (struct opthdr))) { 293227438c18SJon Anderson logerr("mibwalk(): T_OPTMGMT_ACK ctlbuf too " 293327438c18SJon Anderson "short: %d\n", ctlbuf.len); 293427438c18SJon Anderson goto error; 293527438c18SJon Anderson } 293627438c18SJon Anderson if (toa->MGMT_flags != T_SUCCESS) { 293727438c18SJon Anderson logerr("mibwalk(): MGMT_flags != T_SUCCESS: " 293827438c18SJon Anderson "0x%lx\n", toa->MGMT_flags); 293927438c18SJon Anderson goto error; 294027438c18SJon Anderson } 294127438c18SJon Anderson break; 294227438c18SJon Anderson 294327438c18SJon Anderson default: 294427438c18SJon Anderson goto error; 294527438c18SJon Anderson } 294627438c18SJon Anderson /* The following assert also implies MGMT_flags == T_SUCCESS */ 294727438c18SJon Anderson assert(toa->PRIM_type == T_OPTMGMT_ACK); 294827438c18SJon Anderson 294927438c18SJon Anderson /* 295027438c18SJon Anderson * We have reached the end of this T_OPTMGMT_ACK 295127438c18SJon Anderson * message. If this is the last message i.e EOD, 295227438c18SJon Anderson * break, else process the next T_OPTMGMT_ACK msg. 295327438c18SJon Anderson */ 295427438c18SJon Anderson if (rval == 0) { 295527438c18SJon Anderson if (optp->len == 0 && optp->name == 0 && 295627438c18SJon Anderson optp->level == 0) { 295727438c18SJon Anderson /* This is the EOD message. */ 295827438c18SJon Anderson break; 295927438c18SJon Anderson } 296027438c18SJon Anderson /* Not EOD but no data to retrieve */ 296127438c18SJon Anderson continue; 296227438c18SJon Anderson } 296327438c18SJon Anderson 296427438c18SJon Anderson /* 296527438c18SJon Anderson * We should only be here if MOREDATA was set. 296627438c18SJon Anderson * Allocate an empty mib_item_t and link into the list 296727438c18SJon Anderson * of MIB items. 296827438c18SJon Anderson */ 296927438c18SJon Anderson if ((tmp = malloc(sizeof (*tmp))) == NULL) { 297027438c18SJon Anderson logperror("mibwalk(): malloc() failed."); 297127438c18SJon Anderson goto error; 297227438c18SJon Anderson } 297327438c18SJon Anderson if (last_item != NULL) 297427438c18SJon Anderson last_item->mi_next = tmp; 297527438c18SJon Anderson else 297627438c18SJon Anderson head_item = tmp; 297727438c18SJon Anderson last_item = tmp; 297827438c18SJon Anderson last_item->mi_next = NULL; 297927438c18SJon Anderson last_item->mi_opthdr = *optp; 298027438c18SJon Anderson last_item->mi_valp = malloc(optp->len); 298127438c18SJon Anderson if (last_item->mi_valp == NULL) { 298227438c18SJon Anderson logperror("mibwalk(): malloc() failed."); 298327438c18SJon Anderson goto error; 298427438c18SJon Anderson } 298527438c18SJon Anderson 298627438c18SJon Anderson databuf.maxlen = last_item->mi_opthdr.len; 298727438c18SJon Anderson databuf.buf = (char *)last_item->mi_valp; 298827438c18SJon Anderson databuf.len = 0; 298927438c18SJon Anderson 299027438c18SJon Anderson /* Retrieve the actual MIB data */ 299127438c18SJon Anderson for (;;) { 299227438c18SJon Anderson flags = 0; 299327438c18SJon Anderson if ((rval = getmsg(mibfd, NULL, &databuf, 299427438c18SJon Anderson &flags)) != 0) { 299527438c18SJon Anderson if (rval < 0 && errno == EINTR) 299627438c18SJon Anderson continue; 299727438c18SJon Anderson /* 299827438c18SJon Anderson * We shouldn't get MOREDATA here so treat that 299927438c18SJon Anderson * as an error. 300027438c18SJon Anderson */ 300127438c18SJon Anderson logperror("mibwalk(): getmsg(data)"); 300227438c18SJon Anderson goto error; 300327438c18SJon Anderson } 300427438c18SJon Anderson break; 300527438c18SJon Anderson } 300627438c18SJon Anderson } 300727438c18SJon Anderson status = 0; 300827438c18SJon Anderson /* Pass the accumulated MIB data to the supplied function pointer */ 300927438c18SJon Anderson (*proc)(head_item); 301027438c18SJon Anderson error: 301127438c18SJon Anderson while (head_item != NULL) { 301227438c18SJon Anderson tmp = head_item; 301327438c18SJon Anderson head_item = tmp->mi_next; 301427438c18SJon Anderson free(tmp->mi_valp); 301527438c18SJon Anderson free(tmp); 301627438c18SJon Anderson } 301727438c18SJon Anderson return (status); 301827438c18SJon Anderson } 301927438c18SJon Anderson 302027438c18SJon Anderson /* 302127438c18SJon Anderson * Parse the supplied mib2 information to get the size of routing table 302227438c18SJon Anderson * entries. This is needed when running in a branded zone where the 302327438c18SJon Anderson * Solaris application environment and the Solaris kernel may not be the 302427438c18SJon Anderson * the same release version. 302527438c18SJon Anderson */ 302627438c18SJon Anderson static void 302727438c18SJon Anderson mib_get_constants(mib_item_t *item) 302827438c18SJon Anderson { 302927438c18SJon Anderson mib2_ip_t *ipv4; 303027438c18SJon Anderson mib2_ipv6IfStatsEntry_t *ipv6; 303127438c18SJon Anderson 303227438c18SJon Anderson for (; item != NULL; item = item->mi_next) { 303327438c18SJon Anderson if (item->mi_opthdr.name != 0) 303427438c18SJon Anderson continue; 303527438c18SJon Anderson if (item->mi_opthdr.level == MIB2_IP) { 303627438c18SJon Anderson ipv4 = (mib2_ip_t *)item->mi_valp; 303727438c18SJon Anderson ipRouteEntrySize = ipv4->ipRouteEntrySize; 303827438c18SJon Anderson } else if (item->mi_opthdr.level == MIB2_IP6) { 303927438c18SJon Anderson ipv6 = (mib2_ipv6IfStatsEntry_t *)item->mi_valp; 304027438c18SJon Anderson ipv6RouteEntrySize = ipv6->ipv6RouteEntrySize; 304127438c18SJon Anderson } 304227438c18SJon Anderson } 304327438c18SJon Anderson } 3044