10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52074Smeem * Common Development and Distribution License (the "License"). 62074Smeem * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 228485SPeter.Memishian@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include "mpd_defs.h" 270Sstevel@tonic-gate #include "mpd_tables.h" 280Sstevel@tonic-gate 290Sstevel@tonic-gate int debug = 0; /* Debug flag */ 300Sstevel@tonic-gate static int pollfd_num = 0; /* Num. of poll descriptors */ 310Sstevel@tonic-gate static struct pollfd *pollfds = NULL; /* Array of poll descriptors */ 320Sstevel@tonic-gate /* All times below in ms */ 330Sstevel@tonic-gate int user_failure_detection_time; /* user specified failure detection */ 340Sstevel@tonic-gate /* time (fdt) */ 350Sstevel@tonic-gate int user_probe_interval; /* derived from user specified fdt */ 360Sstevel@tonic-gate 378865SJonathan.Anderson@Sun.COM /* 388865SJonathan.Anderson@Sun.COM * Structure to store mib2 information returned by the kernel. 398865SJonathan.Anderson@Sun.COM * This is used to process routing table information. 408865SJonathan.Anderson@Sun.COM */ 418865SJonathan.Anderson@Sun.COM typedef struct mib_item_s { 428865SJonathan.Anderson@Sun.COM struct mib_item_s *mi_next; 438865SJonathan.Anderson@Sun.COM struct opthdr mi_opthdr; 448865SJonathan.Anderson@Sun.COM void *mi_valp; 458865SJonathan.Anderson@Sun.COM } mib_item_t; 468865SJonathan.Anderson@Sun.COM 470Sstevel@tonic-gate static int rtsock_v4; /* AF_INET routing socket */ 480Sstevel@tonic-gate static int rtsock_v6; /* AF_INET6 routing socket */ 490Sstevel@tonic-gate int ifsock_v4 = -1; /* IPv4 socket for ioctls */ 500Sstevel@tonic-gate int ifsock_v6 = -1; /* IPv6 socket for ioctls */ 510Sstevel@tonic-gate static int lsock_v4; /* Listen socket to detect mpathd */ 520Sstevel@tonic-gate static int lsock_v6; /* Listen socket to detect mpathd */ 530Sstevel@tonic-gate static int mibfd = -1; /* fd to get mib info */ 540Sstevel@tonic-gate static boolean_t force_mcast = _B_FALSE; /* Only for test purposes */ 550Sstevel@tonic-gate 560Sstevel@tonic-gate static uint_t last_initifs_time; /* Time when initifs was last run */ 570Sstevel@tonic-gate static char **argv0; /* Saved for re-exec on SIGHUP */ 580Sstevel@tonic-gate boolean_t handle_link_notifications = _B_TRUE; 598865SJonathan.Anderson@Sun.COM static int ipRouteEntrySize; /* Size of IPv4 route entry */ 608865SJonathan.Anderson@Sun.COM static int ipv6RouteEntrySize; /* Size of IPv6 route entry */ 610Sstevel@tonic-gate 620Sstevel@tonic-gate static void initlog(void); 630Sstevel@tonic-gate static void run_timeouts(void); 640Sstevel@tonic-gate static void initifs(void); 650Sstevel@tonic-gate static void check_if_removed(struct phyint_instance *pii); 660Sstevel@tonic-gate static void select_test_ifs(void); 678865SJonathan.Anderson@Sun.COM static void update_router_list(mib_item_t *item); 688865SJonathan.Anderson@Sun.COM static void mib_get_constants(mib_item_t *item); 698865SJonathan.Anderson@Sun.COM static int mibwalk(void (*proc)(mib_item_t *)); 700Sstevel@tonic-gate static void ire_process_v4(mib2_ipRouteEntry_t *buf, size_t len); 710Sstevel@tonic-gate static void ire_process_v6(mib2_ipv6RouteEntry_t *buf, size_t len); 720Sstevel@tonic-gate static void router_add_common(int af, char *ifname, 730Sstevel@tonic-gate struct in6_addr nexthop); 740Sstevel@tonic-gate static void init_router_targets(); 750Sstevel@tonic-gate static void cleanup(void); 760Sstevel@tonic-gate static int setup_listener(int af); 770Sstevel@tonic-gate static void check_config(void); 784770Smeem static void check_testconfig(void); 792496Smeem static void check_addr_unique(struct phyint_instance *, 802496Smeem struct sockaddr_storage *); 810Sstevel@tonic-gate static void init_host_targets(void); 820Sstevel@tonic-gate static void dup_host_targets(struct phyint_instance *desired_pii); 830Sstevel@tonic-gate static void loopback_cmd(int sock, int family); 840Sstevel@tonic-gate static boolean_t daemonize(void); 850Sstevel@tonic-gate static int closefunc(void *, int); 860Sstevel@tonic-gate static unsigned int process_cmd(int newfd, union mi_commands *mpi); 870Sstevel@tonic-gate static unsigned int process_query(int fd, mi_query_t *miq); 888485SPeter.Memishian@Sun.COM static unsigned int send_addrinfo(int fd, ipmp_addrinfo_t *adinfop); 890Sstevel@tonic-gate static unsigned int send_groupinfo(int fd, ipmp_groupinfo_t *grinfop); 900Sstevel@tonic-gate static unsigned int send_grouplist(int fd, ipmp_grouplist_t *grlistp); 910Sstevel@tonic-gate static unsigned int send_ifinfo(int fd, ipmp_ifinfo_t *ifinfop); 920Sstevel@tonic-gate static unsigned int send_result(int fd, unsigned int error, int syserror); 930Sstevel@tonic-gate 948485SPeter.Memishian@Sun.COM addrlist_t *localaddrs; 952250Srk129064 960Sstevel@tonic-gate /* 970Sstevel@tonic-gate * Return the current time in milliseconds (from an arbitrary reference) 980Sstevel@tonic-gate * truncated to fit into an int. Truncation is ok since we are interested 990Sstevel@tonic-gate * only in differences and not the absolute values. 1000Sstevel@tonic-gate */ 1010Sstevel@tonic-gate uint_t 1020Sstevel@tonic-gate getcurrenttime(void) 1030Sstevel@tonic-gate { 1040Sstevel@tonic-gate uint_t cur_time; /* In ms */ 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate /* 1070Sstevel@tonic-gate * Use of a non-user-adjustable source of time is 1080Sstevel@tonic-gate * required. However millisecond precision is sufficient. 1090Sstevel@tonic-gate * divide by 10^6 1100Sstevel@tonic-gate */ 1110Sstevel@tonic-gate cur_time = (uint_t)(gethrtime() / 1000000LL); 1120Sstevel@tonic-gate return (cur_time); 1130Sstevel@tonic-gate } 1140Sstevel@tonic-gate 1154770Smeem uint64_t 1164770Smeem getcurrentsec(void) 1174770Smeem { 1184770Smeem return (gethrtime() / NANOSEC); 1194770Smeem } 1204770Smeem 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * Add fd to the set being polled. Returns 0 if ok; -1 if failed. 1230Sstevel@tonic-gate */ 1240Sstevel@tonic-gate int 1250Sstevel@tonic-gate poll_add(int fd) 1260Sstevel@tonic-gate { 1270Sstevel@tonic-gate int i; 1280Sstevel@tonic-gate int new_num; 1290Sstevel@tonic-gate struct pollfd *newfds; 1300Sstevel@tonic-gate retry: 1310Sstevel@tonic-gate /* Check if already present */ 1320Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 1330Sstevel@tonic-gate if (pollfds[i].fd == fd) 1340Sstevel@tonic-gate return (0); 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate /* Check for empty spot already present */ 1370Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 1380Sstevel@tonic-gate if (pollfds[i].fd == -1) { 1390Sstevel@tonic-gate pollfds[i].fd = fd; 1400Sstevel@tonic-gate return (0); 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate /* Allocate space for 32 more fds and initialize to -1 */ 1450Sstevel@tonic-gate new_num = pollfd_num + 32; 1460Sstevel@tonic-gate newfds = realloc(pollfds, new_num * sizeof (struct pollfd)); 1470Sstevel@tonic-gate if (newfds == NULL) { 1480Sstevel@tonic-gate logperror("poll_add: realloc"); 1490Sstevel@tonic-gate return (-1); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate for (i = pollfd_num; i < new_num; i++) { 1520Sstevel@tonic-gate newfds[i].fd = -1; 1530Sstevel@tonic-gate newfds[i].events = POLLIN; 1540Sstevel@tonic-gate } 1550Sstevel@tonic-gate pollfd_num = new_num; 1560Sstevel@tonic-gate pollfds = newfds; 1570Sstevel@tonic-gate goto retry; 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* 1610Sstevel@tonic-gate * Remove fd from the set being polled. Returns 0 if ok; -1 if failed. 1620Sstevel@tonic-gate */ 1638485SPeter.Memishian@Sun.COM int 1640Sstevel@tonic-gate poll_remove(int fd) 1650Sstevel@tonic-gate { 1660Sstevel@tonic-gate int i; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate /* Check if already present */ 1690Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 1700Sstevel@tonic-gate if (pollfds[i].fd == fd) { 1710Sstevel@tonic-gate pollfds[i].fd = -1; 1720Sstevel@tonic-gate return (0); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate return (-1); 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate /* 1790Sstevel@tonic-gate * Extract information about the phyint instance. If the phyint instance still 1800Sstevel@tonic-gate * exists in the kernel then set pii_in_use, else clear it. check_if_removed() 1810Sstevel@tonic-gate * will use it to detect phyint instances that don't exist any longer and 1820Sstevel@tonic-gate * remove them, from our database of phyint instances. 1830Sstevel@tonic-gate * Return value: 1840Sstevel@tonic-gate * returns true if the phyint instance exists in the kernel, 1850Sstevel@tonic-gate * returns false otherwise 1860Sstevel@tonic-gate */ 1870Sstevel@tonic-gate static boolean_t 1880Sstevel@tonic-gate pii_process(int af, char *name, struct phyint_instance **pii_p) 1890Sstevel@tonic-gate { 1900Sstevel@tonic-gate int err; 1910Sstevel@tonic-gate struct phyint_instance *pii; 1920Sstevel@tonic-gate struct phyint_instance *pii_other; 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate if (debug & D_PHYINT) 1950Sstevel@tonic-gate logdebug("pii_process(%s %s)\n", AF_STR(af), name); 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate pii = phyint_inst_lookup(af, name); 1980Sstevel@tonic-gate if (pii == NULL) { 1990Sstevel@tonic-gate /* 2000Sstevel@tonic-gate * Phyint instance does not exist in our tables, 2010Sstevel@tonic-gate * create new phyint instance 2020Sstevel@tonic-gate */ 2030Sstevel@tonic-gate pii = phyint_inst_init_from_k(af, name); 2040Sstevel@tonic-gate } else { 2050Sstevel@tonic-gate /* Phyint exists in our tables */ 2060Sstevel@tonic-gate err = phyint_inst_update_from_k(pii); 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate switch (err) { 2090Sstevel@tonic-gate case PI_IOCTL_ERROR: 2100Sstevel@tonic-gate /* Some ioctl error. don't change anything */ 2110Sstevel@tonic-gate pii->pii_in_use = 1; 2120Sstevel@tonic-gate break; 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate case PI_GROUP_CHANGED: 2150Sstevel@tonic-gate case PI_IFINDEX_CHANGED: 2160Sstevel@tonic-gate /* 2178485SPeter.Memishian@Sun.COM * Interface index or group membership has changed. 2188485SPeter.Memishian@Sun.COM * Delete the old state and recreate based on the new 2198485SPeter.Memishian@Sun.COM * state (it may no longer be in a group). 2200Sstevel@tonic-gate */ 2210Sstevel@tonic-gate pii_other = phyint_inst_other(pii); 2220Sstevel@tonic-gate if (pii_other != NULL) 2230Sstevel@tonic-gate phyint_inst_delete(pii_other); 2240Sstevel@tonic-gate phyint_inst_delete(pii); 2250Sstevel@tonic-gate pii = phyint_inst_init_from_k(af, name); 2260Sstevel@tonic-gate break; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate case PI_DELETED: 2290Sstevel@tonic-gate /* Phyint instance has disappeared from kernel */ 2300Sstevel@tonic-gate pii->pii_in_use = 0; 2310Sstevel@tonic-gate break; 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate case PI_OK: 2340Sstevel@tonic-gate /* Phyint instance exists and is fine */ 2350Sstevel@tonic-gate pii->pii_in_use = 1; 2360Sstevel@tonic-gate break; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate default: 2390Sstevel@tonic-gate /* Unknown status */ 2400Sstevel@tonic-gate logerr("pii_process: Unknown status %d\n", err); 2410Sstevel@tonic-gate break; 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate *pii_p = pii; 2460Sstevel@tonic-gate if (pii != NULL) 2470Sstevel@tonic-gate return (pii->pii_in_use ? _B_TRUE : _B_FALSE); 2480Sstevel@tonic-gate else 2490Sstevel@tonic-gate return (_B_FALSE); 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * Scan all interfaces to detect changes as well as new and deleted interfaces 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate static void 2560Sstevel@tonic-gate initifs() 2570Sstevel@tonic-gate { 2588485SPeter.Memishian@Sun.COM int i, nlifr; 2590Sstevel@tonic-gate int af; 2600Sstevel@tonic-gate char *cp; 2610Sstevel@tonic-gate char *buf; 2628485SPeter.Memishian@Sun.COM int sockfd; 2638485SPeter.Memishian@Sun.COM uint64_t flags; 2640Sstevel@tonic-gate struct lifnum lifn; 2650Sstevel@tonic-gate struct lifconf lifc; 2668485SPeter.Memishian@Sun.COM struct lifreq lifreq; 2670Sstevel@tonic-gate struct lifreq *lifr; 2680Sstevel@tonic-gate struct logint *li; 2690Sstevel@tonic-gate struct phyint_instance *pii; 2700Sstevel@tonic-gate struct phyint_instance *next_pii; 2718485SPeter.Memishian@Sun.COM struct phyint_group *pg, *next_pg; 2728485SPeter.Memishian@Sun.COM char pi_name[LIFNAMSIZ + 1]; 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate if (debug & D_PHYINT) 2750Sstevel@tonic-gate logdebug("initifs: Scanning interfaces\n"); 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate last_initifs_time = getcurrenttime(); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate /* 2808485SPeter.Memishian@Sun.COM * Free the existing local address list; we'll build a new list below. 2812250Srk129064 */ 2828485SPeter.Memishian@Sun.COM addrlist_free(&localaddrs); 2832250Srk129064 2842250Srk129064 /* 2850Sstevel@tonic-gate * Mark the interfaces so that we can find phyints and logints 2860Sstevel@tonic-gate * which have disappeared from the kernel. pii_process() and 2870Sstevel@tonic-gate * logint_init_from_k() will set {pii,li}_in_use when they find 2880Sstevel@tonic-gate * the interface in the kernel. Also, clear dupaddr bit on probe 2890Sstevel@tonic-gate * logint. check_addr_unique() will set the dupaddr bit on the 2900Sstevel@tonic-gate * probe logint, if the testaddress is not unique. 2910Sstevel@tonic-gate */ 2920Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) { 2930Sstevel@tonic-gate pii->pii_in_use = 0; 2940Sstevel@tonic-gate for (li = pii->pii_logint; li != NULL; li = li->li_next) { 2950Sstevel@tonic-gate li->li_in_use = 0; 2960Sstevel@tonic-gate if (pii->pii_probe_logint == li) 2970Sstevel@tonic-gate li->li_dupaddr = 0; 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate 3018485SPeter.Memishian@Sun.COM /* 3028485SPeter.Memishian@Sun.COM * As above, mark groups so that we can detect IPMP interfaces which 3038485SPeter.Memishian@Sun.COM * have been removed from the kernel. Also, delete the group address 3048485SPeter.Memishian@Sun.COM * list since we'll iteratively recreate it below. 3058485SPeter.Memishian@Sun.COM */ 3068485SPeter.Memishian@Sun.COM for (pg = phyint_groups; pg != NULL; pg = pg->pg_next) { 3078485SPeter.Memishian@Sun.COM pg->pg_in_use = _B_FALSE; 3088485SPeter.Memishian@Sun.COM addrlist_free(&pg->pg_addrs); 3098485SPeter.Memishian@Sun.COM } 3108485SPeter.Memishian@Sun.COM 3110Sstevel@tonic-gate lifn.lifn_family = AF_UNSPEC; 3128485SPeter.Memishian@Sun.COM lifn.lifn_flags = LIFC_ALLZONES | LIFC_UNDER_IPMP; 3138485SPeter.Memishian@Sun.COM again: 3140Sstevel@tonic-gate if (ioctl(ifsock_v4, SIOCGLIFNUM, (char *)&lifn) < 0) { 3158485SPeter.Memishian@Sun.COM logperror("initifs: ioctl (get interface count)"); 3160Sstevel@tonic-gate return; 3170Sstevel@tonic-gate } 3188485SPeter.Memishian@Sun.COM /* 3198485SPeter.Memishian@Sun.COM * Pad the interface count to detect when additional interfaces have 3208485SPeter.Memishian@Sun.COM * been configured between SIOCGLIFNUM and SIOCGLIFCONF. 3218485SPeter.Memishian@Sun.COM */ 3228485SPeter.Memishian@Sun.COM lifn.lifn_count += 4; 3238485SPeter.Memishian@Sun.COM 3248485SPeter.Memishian@Sun.COM if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) { 3250Sstevel@tonic-gate logperror("initifs: calloc"); 3260Sstevel@tonic-gate return; 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate lifc.lifc_family = AF_UNSPEC; 3308485SPeter.Memishian@Sun.COM lifc.lifc_flags = LIFC_ALLZONES | LIFC_UNDER_IPMP; 3318485SPeter.Memishian@Sun.COM lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); 3320Sstevel@tonic-gate lifc.lifc_buf = buf; 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate if (ioctl(ifsock_v4, SIOCGLIFCONF, (char *)&lifc) < 0) { 3358485SPeter.Memishian@Sun.COM logperror("initifs: ioctl (get interface configuration)"); 3360Sstevel@tonic-gate free(buf); 3370Sstevel@tonic-gate return; 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3408485SPeter.Memishian@Sun.COM /* 3418485SPeter.Memishian@Sun.COM * If every lifr_req slot is taken, then additional interfaces must 3428485SPeter.Memishian@Sun.COM * have been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF. 3438485SPeter.Memishian@Sun.COM * Recalculate to make sure we didn't miss any interfaces. 3448485SPeter.Memishian@Sun.COM */ 3458485SPeter.Memishian@Sun.COM nlifr = lifc.lifc_len / sizeof (struct lifreq); 3468485SPeter.Memishian@Sun.COM if (nlifr >= lifn.lifn_count) { 3478485SPeter.Memishian@Sun.COM free(buf); 3488485SPeter.Memishian@Sun.COM goto again; 3498485SPeter.Memishian@Sun.COM } 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate /* 3528485SPeter.Memishian@Sun.COM * Walk through the lifreqs returned by SIOGGLIFCONF, and refresh the 3538485SPeter.Memishian@Sun.COM * global list of addresses, phyint groups, phyints, and logints. 3540Sstevel@tonic-gate */ 3558485SPeter.Memishian@Sun.COM for (lifr = lifc.lifc_req, i = 0; i < nlifr; i++, lifr++) { 3560Sstevel@tonic-gate af = lifr->lifr_addr.ss_family; 3572250Srk129064 sockfd = (af == AF_INET) ? ifsock_v4 : ifsock_v6; 3588485SPeter.Memishian@Sun.COM (void) strlcpy(lifreq.lifr_name, lifr->lifr_name, LIFNAMSIZ); 3592250Srk129064 3602250Srk129064 if (ioctl(sockfd, SIOCGLIFFLAGS, &lifreq) == -1) { 3612250Srk129064 if (errno != ENXIO) 3622250Srk129064 logperror("initifs: ioctl (SIOCGLIFFLAGS)"); 3632250Srk129064 continue; 3642250Srk129064 } 3658485SPeter.Memishian@Sun.COM flags = lifreq.lifr_flags; 3662250Srk129064 3672250Srk129064 /* 3688485SPeter.Memishian@Sun.COM * If the address is IFF_UP, add it to the local address list. 3698485SPeter.Memishian@Sun.COM * (We ignore addresses that aren't IFF_UP since another node 3708485SPeter.Memishian@Sun.COM * might legitimately have that address IFF_UP.) 3712250Srk129064 */ 3728485SPeter.Memishian@Sun.COM if (flags & IFF_UP) { 3738485SPeter.Memishian@Sun.COM (void) addrlist_add(&localaddrs, lifr->lifr_name, flags, 3748485SPeter.Memishian@Sun.COM &lifr->lifr_addr); 3752250Srk129064 } 3762250Srk129064 3772250Srk129064 /* 3788485SPeter.Memishian@Sun.COM * If this address is on an IPMP meta-interface, update our 3798485SPeter.Memishian@Sun.COM * phyint_group information (either by recording that group 3808485SPeter.Memishian@Sun.COM * still exists or creating a new group), and track what 3818485SPeter.Memishian@Sun.COM * group the address is part of. 3828485SPeter.Memishian@Sun.COM */ 3838485SPeter.Memishian@Sun.COM if (flags & IFF_IPMP) { 3848485SPeter.Memishian@Sun.COM if (ioctl(sockfd, SIOCGLIFGROUPNAME, &lifreq) == -1) { 3858485SPeter.Memishian@Sun.COM if (errno != ENXIO) 3868485SPeter.Memishian@Sun.COM logperror("initifs: ioctl " 3878485SPeter.Memishian@Sun.COM "(SIOCGLIFGROUPNAME)"); 3888485SPeter.Memishian@Sun.COM continue; 3898485SPeter.Memishian@Sun.COM } 3908485SPeter.Memishian@Sun.COM 3918485SPeter.Memishian@Sun.COM pg = phyint_group_lookup(lifreq.lifr_groupname); 3928485SPeter.Memishian@Sun.COM if (pg == NULL) { 3938485SPeter.Memishian@Sun.COM pg = phyint_group_create(lifreq.lifr_groupname); 3948485SPeter.Memishian@Sun.COM if (pg == NULL) { 3958485SPeter.Memishian@Sun.COM logerr("initifs: cannot create group " 3968485SPeter.Memishian@Sun.COM "%s\n", lifreq.lifr_groupname); 3978485SPeter.Memishian@Sun.COM continue; 3988485SPeter.Memishian@Sun.COM } 3998485SPeter.Memishian@Sun.COM phyint_group_insert(pg); 4008485SPeter.Memishian@Sun.COM } 4018485SPeter.Memishian@Sun.COM pg->pg_in_use = _B_TRUE; 4028485SPeter.Memishian@Sun.COM 4038485SPeter.Memishian@Sun.COM /* 4048485SPeter.Memishian@Sun.COM * Add this to the group's list of data addresses. 4058485SPeter.Memishian@Sun.COM */ 4068485SPeter.Memishian@Sun.COM if (!addrlist_add(&pg->pg_addrs, lifr->lifr_name, flags, 4078485SPeter.Memishian@Sun.COM &lifr->lifr_addr)) { 4088485SPeter.Memishian@Sun.COM logerr("initifs: insufficient memory to track " 4098485SPeter.Memishian@Sun.COM "data address information for %s\n", 4108485SPeter.Memishian@Sun.COM lifr->lifr_name); 4118485SPeter.Memishian@Sun.COM } 4128485SPeter.Memishian@Sun.COM continue; 4138485SPeter.Memishian@Sun.COM } 4148485SPeter.Memishian@Sun.COM 4158485SPeter.Memishian@Sun.COM /* 4168485SPeter.Memishian@Sun.COM * This isn't an address on an IPMP meta-interface, so it's 4178485SPeter.Memishian@Sun.COM * either on an underlying interface or not related to any 4188485SPeter.Memishian@Sun.COM * group. Update our phyint and logint information (via 4198485SPeter.Memishian@Sun.COM * pii_process() and logint_init_from_k()) -- but first, 4208485SPeter.Memishian@Sun.COM * convert the logint name to a phyint name so we can call 4218485SPeter.Memishian@Sun.COM * pii_process(). 4220Sstevel@tonic-gate */ 4232250Srk129064 (void) strlcpy(pi_name, lifr->lifr_name, sizeof (pi_name)); 4240Sstevel@tonic-gate if ((cp = strchr(pi_name, IF_SEPARATOR)) != NULL) 4250Sstevel@tonic-gate *cp = '\0'; 4260Sstevel@tonic-gate 4278485SPeter.Memishian@Sun.COM if (pii_process(af, pi_name, &pii)) { 4280Sstevel@tonic-gate /* The phyint is fine. So process the logint */ 4290Sstevel@tonic-gate logint_init_from_k(pii, lifr->lifr_name); 4302496Smeem check_addr_unique(pii, &lifr->lifr_addr); 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate free(buf); 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate /* 4368485SPeter.Memishian@Sun.COM * Scan for groups, phyints and logints that have disappeared from the 4370Sstevel@tonic-gate * kernel, and delete them. 4380Sstevel@tonic-gate */ 4394770Smeem for (pii = phyint_instances; pii != NULL; pii = next_pii) { 4400Sstevel@tonic-gate next_pii = pii->pii_next; 4410Sstevel@tonic-gate check_if_removed(pii); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4448485SPeter.Memishian@Sun.COM for (pg = phyint_groups; pg != NULL; pg = next_pg) { 4458485SPeter.Memishian@Sun.COM next_pg = pg->pg_next; 4468485SPeter.Memishian@Sun.COM if (!pg->pg_in_use) { 4478485SPeter.Memishian@Sun.COM phyint_group_delete(pg); 4488485SPeter.Memishian@Sun.COM continue; 4498485SPeter.Memishian@Sun.COM } 4508485SPeter.Memishian@Sun.COM /* 4518485SPeter.Memishian@Sun.COM * Refresh the group's state. This is necessary since the 4528485SPeter.Memishian@Sun.COM * group's state is defined by the set of usable interfaces in 4538485SPeter.Memishian@Sun.COM * the group, and an interface is considered unusable if all 4548485SPeter.Memishian@Sun.COM * of its addresses are down. When an address goes down/up, 4558485SPeter.Memishian@Sun.COM * the RTM_DELADDR/RTM_NEWADDR brings us through here. 4568485SPeter.Memishian@Sun.COM */ 4578485SPeter.Memishian@Sun.COM phyint_group_refresh_state(pg); 4588485SPeter.Memishian@Sun.COM } 4598485SPeter.Memishian@Sun.COM 4600Sstevel@tonic-gate /* 4610Sstevel@tonic-gate * Select a test address for sending probes on each phyint instance 4620Sstevel@tonic-gate */ 4630Sstevel@tonic-gate select_test_ifs(); 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate /* 4668485SPeter.Memishian@Sun.COM * Handle link up/down notifications. 4670Sstevel@tonic-gate */ 4680Sstevel@tonic-gate process_link_state_changes(); 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* 4722496Smeem * Check that a given test address is unique across all of the interfaces in a 4732496Smeem * group. (e.g., IPv6 link-locals may not be inherently unique, and binding 4742496Smeem * to such an (IFF_NOFAILOVER) address can produce unexpected results.) 4754770Smeem * Any issues will be reported by check_testconfig(). 4760Sstevel@tonic-gate */ 4770Sstevel@tonic-gate static void 4782496Smeem check_addr_unique(struct phyint_instance *ourpii, struct sockaddr_storage *ss) 4790Sstevel@tonic-gate { 4802496Smeem struct phyint *pi; 4812496Smeem struct phyint_group *pg; 4822496Smeem struct in6_addr addr; 4830Sstevel@tonic-gate struct phyint_instance *pii; 4840Sstevel@tonic-gate struct sockaddr_in *sin; 4852496Smeem 4862496Smeem if (ss->ss_family == AF_INET) { 4872496Smeem sin = (struct sockaddr_in *)ss; 4880Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &addr); 4890Sstevel@tonic-gate } else { 4902496Smeem assert(ss->ss_family == AF_INET6); 4912496Smeem addr = ((struct sockaddr_in6 *)ss)->sin6_addr; 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate /* 4952496Smeem * For anonymous groups, every interface is assumed to be on its own 4962496Smeem * link, so there is no chance of overlapping addresses. 4970Sstevel@tonic-gate */ 4982496Smeem pg = ourpii->pii_phyint->pi_group; 4992496Smeem if (pg == phyint_anongroup) 5002496Smeem return; 5012496Smeem 5022496Smeem /* 5032496Smeem * Walk the list of phyint instances in the group and check for test 5042496Smeem * addresses matching ours. Of course, we skip ourself. 5052496Smeem */ 5062496Smeem for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext) { 5072496Smeem pii = PHYINT_INSTANCE(pi, ss->ss_family); 5082496Smeem if (pii == NULL || pii == ourpii || 5092496Smeem pii->pii_probe_logint == NULL) 5100Sstevel@tonic-gate continue; 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate /* 5134770Smeem * If this test address is not unique, set the dupaddr bit. 5140Sstevel@tonic-gate */ 5154770Smeem if (IN6_ARE_ADDR_EQUAL(&addr, &pii->pii_probe_logint->li_addr)) 5164770Smeem pii->pii_probe_logint->li_dupaddr = 1; 5170Sstevel@tonic-gate } 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate /* 5210Sstevel@tonic-gate * Stop probing an interface. Called when an interface is offlined. 5220Sstevel@tonic-gate * The probe socket is closed on each interface instance, and the 5230Sstevel@tonic-gate * interface state set to PI_OFFLINE. 5240Sstevel@tonic-gate */ 5258485SPeter.Memishian@Sun.COM void 5260Sstevel@tonic-gate stop_probing(struct phyint *pi) 5270Sstevel@tonic-gate { 5280Sstevel@tonic-gate struct phyint_instance *pii; 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate pii = pi->pi_v4; 5310Sstevel@tonic-gate if (pii != NULL) { 5320Sstevel@tonic-gate if (pii->pii_probe_sock != -1) 5330Sstevel@tonic-gate close_probe_socket(pii, _B_TRUE); 5340Sstevel@tonic-gate pii->pii_probe_logint = NULL; 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate pii = pi->pi_v6; 5380Sstevel@tonic-gate if (pii != NULL) { 5390Sstevel@tonic-gate if (pii->pii_probe_sock != -1) 5400Sstevel@tonic-gate close_probe_socket(pii, _B_TRUE); 5410Sstevel@tonic-gate pii->pii_probe_logint = NULL; 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate phyint_chstate(pi, PI_OFFLINE); 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate 5472074Smeem enum { BAD_TESTFLAGS, OK_TESTFLAGS, BEST_TESTFLAGS }; 5482074Smeem 5490Sstevel@tonic-gate /* 5502074Smeem * Rate the provided test flags. By definition, IFF_NOFAILOVER must be set. 5512074Smeem * IFF_UP must also be set so that the associated address can be used as a 5522074Smeem * source address. Further, we must be able to exchange packets with local 5532074Smeem * destinations, so IFF_NOXMIT and IFF_NOLOCAL must be clear. For historical 5542074Smeem * reasons, we have a proclivity for IFF_DEPRECATED IPv4 test addresses. 5552074Smeem */ 5562074Smeem static int 5572074Smeem rate_testflags(uint64_t flags) 5582074Smeem { 5592074Smeem if ((flags & (IFF_NOFAILOVER | IFF_UP)) != (IFF_NOFAILOVER | IFF_UP)) 5602074Smeem return (BAD_TESTFLAGS); 5612074Smeem 5622074Smeem if ((flags & (IFF_NOXMIT | IFF_NOLOCAL)) != 0) 5632074Smeem return (BAD_TESTFLAGS); 5642074Smeem 5652074Smeem if ((flags & (IFF_IPV6 | IFF_DEPRECATED)) == IFF_DEPRECATED) 5662074Smeem return (BEST_TESTFLAGS); 5672074Smeem 5682074Smeem if ((flags & (IFF_IPV6 | IFF_DEPRECATED)) == IFF_IPV6) 5692074Smeem return (BEST_TESTFLAGS); 5702074Smeem 5712074Smeem return (OK_TESTFLAGS); 5722074Smeem } 5732074Smeem 5742074Smeem /* 5752074Smeem * Attempt to select a test address for each phyint instance. 5762074Smeem * Call phyint_inst_sockinit() to complete the initializations. 5770Sstevel@tonic-gate */ 5780Sstevel@tonic-gate static void 5790Sstevel@tonic-gate select_test_ifs(void) 5800Sstevel@tonic-gate { 5810Sstevel@tonic-gate struct phyint *pi; 5820Sstevel@tonic-gate struct phyint_instance *pii; 5830Sstevel@tonic-gate struct phyint_instance *next_pii; 5842074Smeem struct logint *li; 5852074Smeem struct logint *probe_logint; 5862074Smeem boolean_t target_scan_reqd = _B_FALSE; 5872074Smeem int rating; 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate if (debug & D_PHYINT) 5900Sstevel@tonic-gate logdebug("select_test_ifs\n"); 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate /* 5930Sstevel@tonic-gate * For each phyint instance, do the test address selection 5940Sstevel@tonic-gate */ 5950Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = next_pii) { 5960Sstevel@tonic-gate next_pii = pii->pii_next; 5972074Smeem probe_logint = NULL; 5982074Smeem 5990Sstevel@tonic-gate /* 6008485SPeter.Memishian@Sun.COM * An interface that is offline should not be probed. 6018485SPeter.Memishian@Sun.COM * IFF_OFFLINE interfaces should always be PI_OFFLINE 6020Sstevel@tonic-gate * unless some other entity has set the offline flag. 6030Sstevel@tonic-gate */ 6040Sstevel@tonic-gate if (pii->pii_phyint->pi_flags & IFF_OFFLINE) { 6050Sstevel@tonic-gate if (pii->pii_phyint->pi_state != PI_OFFLINE) { 6060Sstevel@tonic-gate logerr("shouldn't be probing offline" 6074770Smeem " interface %s (state is: %u)." 6084770Smeem " Stopping probes.\n", 6094770Smeem pii->pii_phyint->pi_name, 6104770Smeem pii->pii_phyint->pi_state); 6110Sstevel@tonic-gate stop_probing(pii->pii_phyint); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate continue; 6148485SPeter.Memishian@Sun.COM } else { 6158485SPeter.Memishian@Sun.COM /* 6168485SPeter.Memishian@Sun.COM * If something cleared IFF_OFFLINE (e.g., by accident 6178485SPeter.Memishian@Sun.COM * because the SIOCGLIFFLAGS/SIOCSLIFFLAGS sequence is 6188485SPeter.Memishian@Sun.COM * inherently racy), the phyint may still be offline. 6198485SPeter.Memishian@Sun.COM * Just ignore it. 6208485SPeter.Memishian@Sun.COM */ 6218485SPeter.Memishian@Sun.COM if (pii->pii_phyint->pi_state == PI_OFFLINE) 6228485SPeter.Memishian@Sun.COM continue; 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate 6252074Smeem li = pii->pii_probe_logint; 6262074Smeem if (li != NULL) { 6270Sstevel@tonic-gate /* 6282074Smeem * We've already got a test address; only proceed 6292074Smeem * if it's suboptimal. 6300Sstevel@tonic-gate */ 6312074Smeem if (rate_testflags(li->li_flags) == BEST_TESTFLAGS) 6322074Smeem continue; 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate /* 6360Sstevel@tonic-gate * Walk the logints of this phyint instance, and select 6370Sstevel@tonic-gate * the best available test address 6380Sstevel@tonic-gate */ 6390Sstevel@tonic-gate for (li = pii->pii_logint; li != NULL; li = li->li_next) { 6400Sstevel@tonic-gate /* 6412496Smeem * Skip 0.0.0.0 addresses, as those are never 6422496Smeem * actually usable. 6432496Smeem */ 6442496Smeem if (pii->pii_af == AF_INET && 6452496Smeem IN6_IS_ADDR_V4MAPPED_ANY(&li->li_addr)) 6462496Smeem continue; 6472496Smeem 6482496Smeem /* 6490Sstevel@tonic-gate * Skip any IPv6 logints that are not link-local, 6500Sstevel@tonic-gate * since we should always have a link-local address 6510Sstevel@tonic-gate * anyway and in6_data() expects link-local replies. 6520Sstevel@tonic-gate */ 6530Sstevel@tonic-gate if (pii->pii_af == AF_INET6 && 6540Sstevel@tonic-gate !IN6_IS_ADDR_LINKLOCAL(&li->li_addr)) 6550Sstevel@tonic-gate continue; 6560Sstevel@tonic-gate 6572074Smeem /* 6582074Smeem * Rate the testflags. If we've found an optimal 6592074Smeem * match, then break out; otherwise, record the most 6602074Smeem * recent OK one. 6612074Smeem */ 6622074Smeem rating = rate_testflags(li->li_flags); 6632074Smeem if (rating == BAD_TESTFLAGS) 6642074Smeem continue; 6652074Smeem 6662074Smeem probe_logint = li; 6672074Smeem if (rating == BEST_TESTFLAGS) 6682074Smeem break; 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate /* 6722074Smeem * If the probe logint has changed, ditch the old one. 6730Sstevel@tonic-gate */ 6742074Smeem if (pii->pii_probe_logint != NULL && 6752074Smeem pii->pii_probe_logint != probe_logint) { 6760Sstevel@tonic-gate if (pii->pii_probe_sock != -1) 6770Sstevel@tonic-gate close_probe_socket(pii, _B_TRUE); 6780Sstevel@tonic-gate pii->pii_probe_logint = NULL; 6790Sstevel@tonic-gate } 6800Sstevel@tonic-gate 6812074Smeem if (probe_logint == NULL) { 6820Sstevel@tonic-gate /* 6834770Smeem * We don't have a test address; zero out the probe 6844770Smeem * stats array since it is no longer relevant. 6854770Smeem * Optimize by checking if it is already zeroed out. 6860Sstevel@tonic-gate */ 6870Sstevel@tonic-gate int pr_ndx; 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate pr_ndx = PROBE_INDEX_PREV(pii->pii_probe_next); 6900Sstevel@tonic-gate if (pii->pii_probes[pr_ndx].pr_status != PR_UNUSED) { 6910Sstevel@tonic-gate clear_pii_probe_stats(pii); 6920Sstevel@tonic-gate reset_crtt_all(pii->pii_phyint); 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate continue; 6952074Smeem } else if (probe_logint == pii->pii_probe_logint) { 6960Sstevel@tonic-gate /* 6970Sstevel@tonic-gate * If we didn't find any new test addr, go to the 6980Sstevel@tonic-gate * next phyint. 6990Sstevel@tonic-gate */ 7000Sstevel@tonic-gate continue; 7010Sstevel@tonic-gate } 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate /* 7040Sstevel@tonic-gate * The phyint is either being assigned a new testaddr 7050Sstevel@tonic-gate * or is being assigned a testaddr for the 1st time. 7060Sstevel@tonic-gate * Need to initialize the phyint socket 7070Sstevel@tonic-gate */ 7082074Smeem pii->pii_probe_logint = probe_logint; 7090Sstevel@tonic-gate if (!phyint_inst_sockinit(pii)) { 7100Sstevel@tonic-gate if (debug & D_PHYINT) { 7110Sstevel@tonic-gate logdebug("select_test_ifs: " 7120Sstevel@tonic-gate "phyint_sockinit failed\n"); 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate phyint_inst_delete(pii); 7150Sstevel@tonic-gate continue; 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate /* 7190Sstevel@tonic-gate * This phyint instance is now enabled for probes; this 7200Sstevel@tonic-gate * impacts our state machine in two ways: 7210Sstevel@tonic-gate * 7220Sstevel@tonic-gate * 1. If we're probe *capable* as well (i.e., we have 7230Sstevel@tonic-gate * probe targets) and the interface is in PI_NOTARGETS, 7240Sstevel@tonic-gate * then transition to PI_RUNNING. 7250Sstevel@tonic-gate * 7260Sstevel@tonic-gate * 2. If we're not probe capable, and the other phyint 7270Sstevel@tonic-gate * instance is also not probe capable, and we were in 7280Sstevel@tonic-gate * PI_RUNNING, then transition to PI_NOTARGETS. 7290Sstevel@tonic-gate * 7300Sstevel@tonic-gate * Also see the state diagram in mpd_probe.c. 7310Sstevel@tonic-gate */ 7320Sstevel@tonic-gate if (PROBE_CAPABLE(pii)) { 7330Sstevel@tonic-gate if (pii->pii_phyint->pi_state == PI_NOTARGETS) 7340Sstevel@tonic-gate phyint_chstate(pii->pii_phyint, PI_RUNNING); 7350Sstevel@tonic-gate } else if (!PROBE_CAPABLE(phyint_inst_other(pii))) { 7360Sstevel@tonic-gate if (pii->pii_phyint->pi_state == PI_RUNNING) 7370Sstevel@tonic-gate phyint_chstate(pii->pii_phyint, PI_NOTARGETS); 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate /* 7410Sstevel@tonic-gate * If no targets are currently known for this phyint 7420Sstevel@tonic-gate * we need to call init_router_targets. Since 7430Sstevel@tonic-gate * init_router_targets() initializes the list of targets 7440Sstevel@tonic-gate * for all phyints it is done below the loop. 7450Sstevel@tonic-gate */ 7460Sstevel@tonic-gate if (pii->pii_targets == NULL) 7470Sstevel@tonic-gate target_scan_reqd = _B_TRUE; 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * Start the probe timer for this instance. 7510Sstevel@tonic-gate */ 7522496Smeem if (!pii->pii_basetime_inited && PROBE_ENABLED(pii)) { 7530Sstevel@tonic-gate start_timer(pii); 7540Sstevel@tonic-gate pii->pii_basetime_inited = 1; 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate /* 7598485SPeter.Memishian@Sun.COM * Scan the interface list for any interfaces that are PI_FAILED or 7608485SPeter.Memishian@Sun.COM * PI_NOTARGETS but no longer enabled to send probes, and call 7618485SPeter.Memishian@Sun.COM * phyint_check_for_repair() to see if the link state indicates that 7628485SPeter.Memishian@Sun.COM * the interface should be repaired. Also see the state diagram in 7630Sstevel@tonic-gate * mpd_probe.c. 7640Sstevel@tonic-gate */ 7650Sstevel@tonic-gate for (pi = phyints; pi != NULL; pi = pi->pi_next) { 7668485SPeter.Memishian@Sun.COM if ((!PROBE_ENABLED(pi->pi_v4) && !PROBE_ENABLED(pi->pi_v6)) && 7678485SPeter.Memishian@Sun.COM (pi->pi_state == PI_FAILED || 7688485SPeter.Memishian@Sun.COM pi->pi_state == PI_NOTARGETS)) { 7690Sstevel@tonic-gate phyint_check_for_repair(pi); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7734770Smeem check_testconfig(); 7744770Smeem 7750Sstevel@tonic-gate /* 7760Sstevel@tonic-gate * Try to populate the target list. init_router_targets populates 7770Sstevel@tonic-gate * the target list from the routing table. If our target list is 7780Sstevel@tonic-gate * still empty, init_host_targets adds host targets based on the 7790Sstevel@tonic-gate * host target list of other phyints in the group. 7800Sstevel@tonic-gate */ 7810Sstevel@tonic-gate if (target_scan_reqd) { 7820Sstevel@tonic-gate init_router_targets(); 7830Sstevel@tonic-gate init_host_targets(); 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate /* 7886578Smeem * Check test address configuration, and log notices/errors if appropriate. 7896578Smeem * Note that this function only logs pre-existing conditions (e.g., that 7906578Smeem * probe-based failure detection is disabled). 7914770Smeem */ 7924770Smeem static void 7934770Smeem check_testconfig(void) 7944770Smeem { 7954770Smeem struct phyint *pi; 7964770Smeem struct logint *li; 7974770Smeem char abuf[INET6_ADDRSTRLEN]; 7986578Smeem int pri; 7994770Smeem 8004770Smeem for (pi = phyints; pi != NULL; pi = pi->pi_next) { 8014770Smeem if (pi->pi_flags & IFF_OFFLINE) 8024770Smeem continue; 8034770Smeem 8044770Smeem if (PROBE_ENABLED(pi->pi_v4) || PROBE_ENABLED(pi->pi_v6)) { 8054770Smeem if (pi->pi_taddrmsg_printed || 8064770Smeem pi->pi_duptaddrmsg_printed) { 8076578Smeem if (pi->pi_duptaddrmsg_printed) 8086578Smeem pri = LOG_ERR; 8096578Smeem else 8106578Smeem pri = LOG_INFO; 8116578Smeem logmsg(pri, "Test address now configured on " 8124770Smeem "interface %s; enabling probe-based " 8134770Smeem "failure detection on it\n", pi->pi_name); 8144770Smeem pi->pi_taddrmsg_printed = 0; 8154770Smeem pi->pi_duptaddrmsg_printed = 0; 8164770Smeem } 8174770Smeem continue; 8184770Smeem } 8194770Smeem 8204770Smeem li = NULL; 8214770Smeem if (pi->pi_v4 != NULL && pi->pi_v4->pii_probe_logint != NULL && 8224770Smeem pi->pi_v4->pii_probe_logint->li_dupaddr) 8234770Smeem li = pi->pi_v4->pii_probe_logint; 8244770Smeem 8254770Smeem if (pi->pi_v6 != NULL && pi->pi_v6->pii_probe_logint != NULL && 8264770Smeem pi->pi_v6->pii_probe_logint->li_dupaddr) 8274770Smeem li = pi->pi_v6->pii_probe_logint; 8284770Smeem 8298485SPeter.Memishian@Sun.COM if (li != NULL && li->li_dupaddr) { 8308485SPeter.Memishian@Sun.COM if (pi->pi_duptaddrmsg_printed) 8318485SPeter.Memishian@Sun.COM continue; 8328485SPeter.Memishian@Sun.COM logerr("Test address %s is not unique in group; " 8338485SPeter.Memishian@Sun.COM "disabling probe-based failure detection on %s\n", 8348485SPeter.Memishian@Sun.COM pr_addr(li->li_phyint_inst->pii_af, 8358485SPeter.Memishian@Sun.COM li->li_addr, abuf, sizeof (abuf)), pi->pi_name); 8368485SPeter.Memishian@Sun.COM pi->pi_duptaddrmsg_printed = 1; 8374770Smeem continue; 8384770Smeem } 8394770Smeem 8404770Smeem if (getcurrentsec() < pi->pi_taddrthresh) 8414770Smeem continue; 8424770Smeem 8434770Smeem if (!pi->pi_taddrmsg_printed) { 8446578Smeem logtrace("No test address configured on interface %s; " 8454770Smeem "disabling probe-based failure detection on it\n", 8464770Smeem pi->pi_name); 8474770Smeem pi->pi_taddrmsg_printed = 1; 8484770Smeem } 8494770Smeem } 8504770Smeem } 8514770Smeem 8524770Smeem /* 8530Sstevel@tonic-gate * Check phyint group configuration, to detect any inconsistencies, 8540Sstevel@tonic-gate * and log an error message. This is called from runtimeouts every 8550Sstevel@tonic-gate * 20 secs. But the error message is displayed once. If the 8560Sstevel@tonic-gate * consistency is resolved by the admin, a recovery message is displayed 8570Sstevel@tonic-gate * once. 8580Sstevel@tonic-gate */ 8590Sstevel@tonic-gate static void 8600Sstevel@tonic-gate check_config(void) 8610Sstevel@tonic-gate { 8620Sstevel@tonic-gate struct phyint_group *pg; 8630Sstevel@tonic-gate struct phyint *pi; 8640Sstevel@tonic-gate boolean_t v4_in_group; 8650Sstevel@tonic-gate boolean_t v6_in_group; 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate /* 8688485SPeter.Memishian@Sun.COM * All phyints of a group must be homogeneous to ensure that they can 8698485SPeter.Memishian@Sun.COM * take over for one another. If any phyint in a group has IPv4 8708485SPeter.Memishian@Sun.COM * plumbed, check that all phyints have IPv4 plumbed. Do a similar 8718485SPeter.Memishian@Sun.COM * check for IPv6. 8720Sstevel@tonic-gate */ 8730Sstevel@tonic-gate for (pg = phyint_groups; pg != NULL; pg = pg->pg_next) { 8740Sstevel@tonic-gate if (pg == phyint_anongroup) 8750Sstevel@tonic-gate continue; 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate v4_in_group = _B_FALSE; 8780Sstevel@tonic-gate v6_in_group = _B_FALSE; 8790Sstevel@tonic-gate /* 8800Sstevel@tonic-gate * 1st pass. Determine if at least 1 phyint in the group 8810Sstevel@tonic-gate * has IPv4 plumbed and if so set v4_in_group to true. 8820Sstevel@tonic-gate * Repeat similarly for IPv6. 8830Sstevel@tonic-gate */ 8840Sstevel@tonic-gate for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext) { 8850Sstevel@tonic-gate if (pi->pi_v4 != NULL) 8860Sstevel@tonic-gate v4_in_group = _B_TRUE; 8870Sstevel@tonic-gate if (pi->pi_v6 != NULL) 8880Sstevel@tonic-gate v6_in_group = _B_TRUE; 8890Sstevel@tonic-gate } 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate /* 8920Sstevel@tonic-gate * 2nd pass. If v4_in_group is true, check that phyint 8930Sstevel@tonic-gate * has IPv4 plumbed. Repeat similarly for IPv6. Print 8940Sstevel@tonic-gate * out a message the 1st time only. 8950Sstevel@tonic-gate */ 8960Sstevel@tonic-gate for (pi = pg->pg_phyint; pi != NULL; pi = pi->pi_pgnext) { 8970Sstevel@tonic-gate if (pi->pi_flags & IFF_OFFLINE) 8980Sstevel@tonic-gate continue; 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate if (v4_in_group == _B_TRUE && pi->pi_v4 == NULL) { 9010Sstevel@tonic-gate if (!pi->pi_cfgmsg_printed) { 9028485SPeter.Memishian@Sun.COM logerr("IP interface %s in group %s is" 9038485SPeter.Memishian@Sun.COM " not plumbed for IPv4, affecting" 9048485SPeter.Memishian@Sun.COM " IPv4 connectivity\n", 9050Sstevel@tonic-gate pi->pi_name, 9060Sstevel@tonic-gate pi->pi_group->pg_name); 9070Sstevel@tonic-gate pi->pi_cfgmsg_printed = 1; 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate } else if (v6_in_group == _B_TRUE && 9100Sstevel@tonic-gate pi->pi_v6 == NULL) { 9110Sstevel@tonic-gate if (!pi->pi_cfgmsg_printed) { 9128485SPeter.Memishian@Sun.COM logerr("IP interface %s in group %s is" 9138485SPeter.Memishian@Sun.COM " not plumbed for IPv6, affecting" 9148485SPeter.Memishian@Sun.COM " IPv6 connectivity\n", 9150Sstevel@tonic-gate pi->pi_name, 9160Sstevel@tonic-gate pi->pi_group->pg_name); 9170Sstevel@tonic-gate pi->pi_cfgmsg_printed = 1; 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate } else { 9200Sstevel@tonic-gate /* 9210Sstevel@tonic-gate * The phyint matches the group configuration, 9220Sstevel@tonic-gate * if we have reached this point. If it was 9230Sstevel@tonic-gate * improperly configured earlier, log an 9240Sstevel@tonic-gate * error recovery message 9250Sstevel@tonic-gate */ 9260Sstevel@tonic-gate if (pi->pi_cfgmsg_printed) { 9278485SPeter.Memishian@Sun.COM logerr("IP interface %s is now" 9288485SPeter.Memishian@Sun.COM " consistent with group %s " 9298485SPeter.Memishian@Sun.COM " and connectivity is restored\n", 9308485SPeter.Memishian@Sun.COM pi->pi_name, pi->pi_group->pg_name); 9310Sstevel@tonic-gate pi->pi_cfgmsg_printed = 0; 9320Sstevel@tonic-gate } 9330Sstevel@tonic-gate } 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate } 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate /* 9400Sstevel@tonic-gate * Timer mechanism using relative time (in milliseconds) from the 9410Sstevel@tonic-gate * previous timer event. Timers exceeding TIMER_INFINITY milliseconds 9420Sstevel@tonic-gate * will fire after TIMER_INFINITY milliseconds. 9430Sstevel@tonic-gate * Unsigned arithmetic note: We assume a 32-bit circular sequence space for 9440Sstevel@tonic-gate * time values. Hence 2 consecutive timer events cannot be spaced farther 9450Sstevel@tonic-gate * than 0x7fffffff. We call this TIMER_INFINITY, and it is the maximum value 9460Sstevel@tonic-gate * that can be passed for the delay parameter of timer_schedule() 9470Sstevel@tonic-gate */ 9480Sstevel@tonic-gate static uint_t timer_next; /* Currently scheduled timeout */ 9490Sstevel@tonic-gate static boolean_t timer_active = _B_FALSE; /* SIGALRM has not yet occurred */ 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate static void 9520Sstevel@tonic-gate timer_init(void) 9530Sstevel@tonic-gate { 9540Sstevel@tonic-gate timer_next = getcurrenttime() + TIMER_INFINITY; 9550Sstevel@tonic-gate /* 9560Sstevel@tonic-gate * The call to run_timeouts() will get the timer started 9570Sstevel@tonic-gate * Since there are no phyints at this point, the timer will 9580Sstevel@tonic-gate * be set for IF_SCAN_INTERVAL ms. 9590Sstevel@tonic-gate */ 9600Sstevel@tonic-gate run_timeouts(); 9610Sstevel@tonic-gate } 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate /* 9640Sstevel@tonic-gate * Make sure the next SIGALRM occurs delay milliseconds from the current 9650Sstevel@tonic-gate * time if not earlier. We are interested only in time differences. 9660Sstevel@tonic-gate */ 9670Sstevel@tonic-gate void 9680Sstevel@tonic-gate timer_schedule(uint_t delay) 9690Sstevel@tonic-gate { 9700Sstevel@tonic-gate uint_t now; 9710Sstevel@tonic-gate struct itimerval itimerval; 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate if (debug & D_TIMER) 9740Sstevel@tonic-gate logdebug("timer_schedule(%u)\n", delay); 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate assert(delay <= TIMER_INFINITY); 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate now = getcurrenttime(); 9790Sstevel@tonic-gate if (delay == 0) { 9800Sstevel@tonic-gate /* Minimum allowed delay */ 9810Sstevel@tonic-gate delay = 1; 9820Sstevel@tonic-gate } 9830Sstevel@tonic-gate /* Will this timer occur before the currently scheduled SIGALRM? */ 9840Sstevel@tonic-gate if (timer_active && TIME_GE(now + delay, timer_next)) { 9850Sstevel@tonic-gate if (debug & D_TIMER) { 9860Sstevel@tonic-gate logdebug("timer_schedule(%u) - no action: " 9870Sstevel@tonic-gate "now %u next %u\n", delay, now, timer_next); 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate return; 9900Sstevel@tonic-gate } 9910Sstevel@tonic-gate timer_next = now + delay; 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate itimerval.it_value.tv_sec = delay / 1000; 9940Sstevel@tonic-gate itimerval.it_value.tv_usec = (delay % 1000) * 1000; 9950Sstevel@tonic-gate itimerval.it_interval.tv_sec = 0; 9960Sstevel@tonic-gate itimerval.it_interval.tv_usec = 0; 9970Sstevel@tonic-gate if (debug & D_TIMER) { 9980Sstevel@tonic-gate logdebug("timer_schedule(%u): sec %ld usec %ld\n", 9990Sstevel@tonic-gate delay, itimerval.it_value.tv_sec, 10000Sstevel@tonic-gate itimerval.it_value.tv_usec); 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate timer_active = _B_TRUE; 10030Sstevel@tonic-gate if (setitimer(ITIMER_REAL, &itimerval, NULL) < 0) { 10040Sstevel@tonic-gate logperror("timer_schedule: setitimer"); 10050Sstevel@tonic-gate exit(2); 10060Sstevel@tonic-gate } 10070Sstevel@tonic-gate } 10080Sstevel@tonic-gate 10099416SPeter.Memishian@Sun.COM static void 10109416SPeter.Memishian@Sun.COM timer_cancel(void) 10119416SPeter.Memishian@Sun.COM { 10129416SPeter.Memishian@Sun.COM struct itimerval itimerval; 10139416SPeter.Memishian@Sun.COM 10149416SPeter.Memishian@Sun.COM if (debug & D_TIMER) 10159416SPeter.Memishian@Sun.COM logdebug("timer_cancel()\n"); 10169416SPeter.Memishian@Sun.COM 10179416SPeter.Memishian@Sun.COM bzero(&itimerval, sizeof (itimerval)); 10189416SPeter.Memishian@Sun.COM if (setitimer(ITIMER_REAL, &itimerval, NULL) < 0) 10199416SPeter.Memishian@Sun.COM logperror("timer_cancel: setitimer"); 10209416SPeter.Memishian@Sun.COM } 10219416SPeter.Memishian@Sun.COM 10220Sstevel@tonic-gate /* 10230Sstevel@tonic-gate * Timer has fired. Determine when the next timer event will occur by asking 10240Sstevel@tonic-gate * all the timer routines. Should not be called from a timer routine. 10250Sstevel@tonic-gate */ 10260Sstevel@tonic-gate static void 10270Sstevel@tonic-gate run_timeouts(void) 10280Sstevel@tonic-gate { 10290Sstevel@tonic-gate uint_t next; 10300Sstevel@tonic-gate uint_t next_event_time; 10310Sstevel@tonic-gate struct phyint_instance *pii; 10320Sstevel@tonic-gate struct phyint_instance *next_pii; 10330Sstevel@tonic-gate static boolean_t timeout_running; 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate /* assert that recursive timeouts don't happen. */ 10360Sstevel@tonic-gate assert(!timeout_running); 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate timeout_running = _B_TRUE; 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate if (debug & D_TIMER) 10410Sstevel@tonic-gate logdebug("run_timeouts()\n"); 10420Sstevel@tonic-gate 10434770Smeem if ((getcurrenttime() - last_initifs_time) > IF_SCAN_INTERVAL) { 10444770Smeem initifs(); 10454770Smeem check_config(); 10464770Smeem } 10474770Smeem 10480Sstevel@tonic-gate next = TIMER_INFINITY; 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = next_pii) { 10510Sstevel@tonic-gate next_pii = pii->pii_next; 10520Sstevel@tonic-gate next_event_time = phyint_inst_timer(pii); 10530Sstevel@tonic-gate if (next_event_time != TIMER_INFINITY && next_event_time < next) 10540Sstevel@tonic-gate next = next_event_time; 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate if (debug & D_TIMER) { 10570Sstevel@tonic-gate logdebug("run_timeouts(%s %s): next scheduled for" 10580Sstevel@tonic-gate " this phyint inst %u, next scheduled global" 10590Sstevel@tonic-gate " %u ms\n", 10600Sstevel@tonic-gate AF_STR(pii->pii_af), pii->pii_phyint->pi_name, 10610Sstevel@tonic-gate next_event_time, next); 10620Sstevel@tonic-gate } 10630Sstevel@tonic-gate } 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate /* 10660Sstevel@tonic-gate * Make sure initifs() is called at least once every 10670Sstevel@tonic-gate * IF_SCAN_INTERVAL, to make sure that we are in sync 10680Sstevel@tonic-gate * with the kernel, in case we have missed any routing 10690Sstevel@tonic-gate * socket messages. 10700Sstevel@tonic-gate */ 10710Sstevel@tonic-gate if (next > IF_SCAN_INTERVAL) 10720Sstevel@tonic-gate next = IF_SCAN_INTERVAL; 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate if (debug & D_TIMER) 10750Sstevel@tonic-gate logdebug("run_timeouts: %u ms\n", next); 10760Sstevel@tonic-gate 10770Sstevel@tonic-gate timer_schedule(next); 10780Sstevel@tonic-gate timeout_running = _B_FALSE; 10790Sstevel@tonic-gate } 10800Sstevel@tonic-gate 10810Sstevel@tonic-gate static int eventpipe_read = -1; /* Used for synchronous signal delivery */ 10820Sstevel@tonic-gate static int eventpipe_write = -1; 10838485SPeter.Memishian@Sun.COM boolean_t cleanup_started = _B_FALSE; /* true if we're going away */ 10848485SPeter.Memishian@Sun.COM 10850Sstevel@tonic-gate /* 10860Sstevel@tonic-gate * Ensure that signals are processed synchronously with the rest of 10870Sstevel@tonic-gate * the code by just writing a one character signal number on the pipe. 10880Sstevel@tonic-gate * The poll loop will pick this up and process the signal event. 10890Sstevel@tonic-gate */ 10900Sstevel@tonic-gate static void 10910Sstevel@tonic-gate sig_handler(int signo) 10920Sstevel@tonic-gate { 10930Sstevel@tonic-gate uchar_t buf = (uchar_t)signo; 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate /* 10960Sstevel@tonic-gate * Don't write to pipe if cleanup has already begun. cleanup() 10970Sstevel@tonic-gate * might have closed the pipe already 10980Sstevel@tonic-gate */ 10990Sstevel@tonic-gate if (cleanup_started) 11000Sstevel@tonic-gate return; 11010Sstevel@tonic-gate 11020Sstevel@tonic-gate if (eventpipe_write == -1) { 11030Sstevel@tonic-gate logerr("sig_handler: no pipe found\n"); 11040Sstevel@tonic-gate return; 11050Sstevel@tonic-gate } 11060Sstevel@tonic-gate if (write(eventpipe_write, &buf, sizeof (buf)) < 0) 11070Sstevel@tonic-gate logperror("sig_handler: write"); 11080Sstevel@tonic-gate } 11090Sstevel@tonic-gate 11100Sstevel@tonic-gate extern struct probes_missed probes_missed; 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate /* 11130Sstevel@tonic-gate * Pick up a signal "byte" from the pipe and process it. 11140Sstevel@tonic-gate */ 11150Sstevel@tonic-gate static void 11160Sstevel@tonic-gate in_signal(int fd) 11170Sstevel@tonic-gate { 11180Sstevel@tonic-gate uchar_t buf; 11190Sstevel@tonic-gate uint64_t sent, acked, lost, unacked, unknown; 11200Sstevel@tonic-gate struct phyint_instance *pii; 11210Sstevel@tonic-gate int pr_ndx; 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate switch (read(fd, &buf, sizeof (buf))) { 11240Sstevel@tonic-gate case -1: 11250Sstevel@tonic-gate logperror("in_signal: read"); 11260Sstevel@tonic-gate exit(1); 11270Sstevel@tonic-gate /* NOTREACHED */ 11280Sstevel@tonic-gate case 1: 11290Sstevel@tonic-gate break; 11300Sstevel@tonic-gate case 0: 11310Sstevel@tonic-gate logerr("in_signal: read end of file\n"); 11320Sstevel@tonic-gate exit(1); 11330Sstevel@tonic-gate /* NOTREACHED */ 11340Sstevel@tonic-gate default: 11350Sstevel@tonic-gate logerr("in_signal: read > 1\n"); 11360Sstevel@tonic-gate exit(1); 11370Sstevel@tonic-gate } 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate if (debug & D_TIMER) 11400Sstevel@tonic-gate logdebug("in_signal() got %d\n", buf); 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate switch (buf) { 11430Sstevel@tonic-gate case SIGALRM: 11440Sstevel@tonic-gate if (debug & D_TIMER) { 11450Sstevel@tonic-gate uint_t now = getcurrenttime(); 11460Sstevel@tonic-gate 11470Sstevel@tonic-gate logdebug("in_signal(SIGALRM) delta %u\n", 11480Sstevel@tonic-gate now - timer_next); 11490Sstevel@tonic-gate } 11500Sstevel@tonic-gate timer_active = _B_FALSE; 11510Sstevel@tonic-gate run_timeouts(); 11520Sstevel@tonic-gate break; 11530Sstevel@tonic-gate case SIGUSR1: 11540Sstevel@tonic-gate logdebug("Printing configuration:\n"); 11550Sstevel@tonic-gate /* Print out the internal tables */ 11560Sstevel@tonic-gate phyint_inst_print_all(); 11570Sstevel@tonic-gate 11580Sstevel@tonic-gate /* 11590Sstevel@tonic-gate * Print out the accumulated statistics about missed 11600Sstevel@tonic-gate * probes (happens due to scheduling delay). 11610Sstevel@tonic-gate */ 11620Sstevel@tonic-gate logerr("Missed sending total of %d probes spread over" 11630Sstevel@tonic-gate " %d occurrences\n", probes_missed.pm_nprobes, 11640Sstevel@tonic-gate probes_missed.pm_ntimes); 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate /* 11670Sstevel@tonic-gate * Print out the accumulated statistics about probes 11680Sstevel@tonic-gate * that were sent. 11690Sstevel@tonic-gate */ 11700Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; 11710Sstevel@tonic-gate pii = pii->pii_next) { 11720Sstevel@tonic-gate unacked = 0; 11730Sstevel@tonic-gate acked = pii->pii_cum_stats.acked; 11740Sstevel@tonic-gate lost = pii->pii_cum_stats.lost; 11750Sstevel@tonic-gate sent = pii->pii_cum_stats.sent; 11760Sstevel@tonic-gate unknown = pii->pii_cum_stats.unknown; 11770Sstevel@tonic-gate for (pr_ndx = 0; pr_ndx < PROBE_STATS_COUNT; pr_ndx++) { 11780Sstevel@tonic-gate switch (pii->pii_probes[pr_ndx].pr_status) { 11790Sstevel@tonic-gate case PR_ACKED: 11800Sstevel@tonic-gate acked++; 11810Sstevel@tonic-gate break; 11820Sstevel@tonic-gate case PR_LOST: 11830Sstevel@tonic-gate lost++; 11840Sstevel@tonic-gate break; 11850Sstevel@tonic-gate case PR_UNACKED: 11860Sstevel@tonic-gate unacked++; 11870Sstevel@tonic-gate break; 11880Sstevel@tonic-gate } 11890Sstevel@tonic-gate } 11900Sstevel@tonic-gate logerr("\nProbe stats on (%s %s)\n" 11910Sstevel@tonic-gate "Number of probes sent %lld\n" 11920Sstevel@tonic-gate "Number of probe acks received %lld\n" 11930Sstevel@tonic-gate "Number of probes/acks lost %lld\n" 11948485SPeter.Memishian@Sun.COM "Number of valid unacknowledged probes %lld\n" 11950Sstevel@tonic-gate "Number of ambiguous probe acks received %lld\n", 11960Sstevel@tonic-gate AF_STR(pii->pii_af), pii->pii_name, 11970Sstevel@tonic-gate sent, acked, lost, unacked, unknown); 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate break; 12000Sstevel@tonic-gate case SIGHUP: 12010Sstevel@tonic-gate logerr("SIGHUP: restart and reread config file\n"); 12029416SPeter.Memishian@Sun.COM /* 12039416SPeter.Memishian@Sun.COM * Cancel the interval timer. Needed since setitimer() uses 12049416SPeter.Memishian@Sun.COM * alarm() and the time left is inherited across exec(), and 12059416SPeter.Memishian@Sun.COM * thus the SIGALRM may be delivered before a handler has been 12069416SPeter.Memishian@Sun.COM * setup, causing in.mpathd to erroneously exit. 12079416SPeter.Memishian@Sun.COM */ 12089416SPeter.Memishian@Sun.COM timer_cancel(); 12090Sstevel@tonic-gate cleanup(); 12100Sstevel@tonic-gate (void) execv(argv0[0], argv0); 12110Sstevel@tonic-gate _exit(0177); 12120Sstevel@tonic-gate /* NOTREACHED */ 12130Sstevel@tonic-gate case SIGINT: 12140Sstevel@tonic-gate case SIGTERM: 12150Sstevel@tonic-gate case SIGQUIT: 12160Sstevel@tonic-gate cleanup(); 12170Sstevel@tonic-gate exit(0); 12180Sstevel@tonic-gate /* NOTREACHED */ 12190Sstevel@tonic-gate default: 12200Sstevel@tonic-gate logerr("in_signal: unknown signal: %d\n", buf); 12210Sstevel@tonic-gate } 12220Sstevel@tonic-gate } 12230Sstevel@tonic-gate 12240Sstevel@tonic-gate static void 12250Sstevel@tonic-gate cleanup(void) 12260Sstevel@tonic-gate { 12270Sstevel@tonic-gate struct phyint_instance *pii; 12280Sstevel@tonic-gate struct phyint_instance *next_pii; 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate /* 12310Sstevel@tonic-gate * Make sure that we don't write to eventpipe in 12320Sstevel@tonic-gate * sig_handler() if any signal notably SIGALRM, 12330Sstevel@tonic-gate * occurs after we close the eventpipe descriptor below 12340Sstevel@tonic-gate */ 12350Sstevel@tonic-gate cleanup_started = _B_TRUE; 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = next_pii) { 12380Sstevel@tonic-gate next_pii = pii->pii_next; 12390Sstevel@tonic-gate phyint_inst_delete(pii); 12400Sstevel@tonic-gate } 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate (void) close(ifsock_v4); 12430Sstevel@tonic-gate (void) close(ifsock_v6); 12440Sstevel@tonic-gate (void) close(rtsock_v4); 12450Sstevel@tonic-gate (void) close(rtsock_v6); 12460Sstevel@tonic-gate (void) close(lsock_v4); 12470Sstevel@tonic-gate (void) close(lsock_v6); 12480Sstevel@tonic-gate (void) close(0); 12490Sstevel@tonic-gate (void) close(1); 12500Sstevel@tonic-gate (void) close(2); 12510Sstevel@tonic-gate (void) close(mibfd); 12520Sstevel@tonic-gate (void) close(eventpipe_read); 12530Sstevel@tonic-gate (void) close(eventpipe_write); 12540Sstevel@tonic-gate } 12550Sstevel@tonic-gate 12560Sstevel@tonic-gate /* 12570Sstevel@tonic-gate * Create pipe for signal delivery and set up signal handlers. 12580Sstevel@tonic-gate */ 12590Sstevel@tonic-gate static void 12600Sstevel@tonic-gate setup_eventpipe(void) 12610Sstevel@tonic-gate { 12620Sstevel@tonic-gate int fds[2]; 12630Sstevel@tonic-gate struct sigaction act; 12640Sstevel@tonic-gate 12650Sstevel@tonic-gate if ((pipe(fds)) < 0) { 12660Sstevel@tonic-gate logperror("setup_eventpipe: pipe"); 12670Sstevel@tonic-gate exit(1); 12680Sstevel@tonic-gate } 12690Sstevel@tonic-gate eventpipe_read = fds[0]; 12700Sstevel@tonic-gate eventpipe_write = fds[1]; 12710Sstevel@tonic-gate if (poll_add(eventpipe_read) == -1) { 12720Sstevel@tonic-gate exit(1); 12730Sstevel@tonic-gate } 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate act.sa_handler = sig_handler; 12760Sstevel@tonic-gate act.sa_flags = SA_RESTART; 12770Sstevel@tonic-gate (void) sigaction(SIGALRM, &act, NULL); 12780Sstevel@tonic-gate 12790Sstevel@tonic-gate (void) sigset(SIGHUP, sig_handler); 12800Sstevel@tonic-gate (void) sigset(SIGUSR1, sig_handler); 12810Sstevel@tonic-gate (void) sigset(SIGTERM, sig_handler); 12820Sstevel@tonic-gate (void) sigset(SIGINT, sig_handler); 12830Sstevel@tonic-gate (void) sigset(SIGQUIT, sig_handler); 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate /* 12870Sstevel@tonic-gate * Create a routing socket for receiving RTM_IFINFO messages. 12880Sstevel@tonic-gate */ 12890Sstevel@tonic-gate static int 12900Sstevel@tonic-gate setup_rtsock(int af) 12910Sstevel@tonic-gate { 12920Sstevel@tonic-gate int s; 12930Sstevel@tonic-gate int flags; 12948485SPeter.Memishian@Sun.COM int aware = RTAW_UNDER_IPMP; 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate s = socket(PF_ROUTE, SOCK_RAW, af); 12970Sstevel@tonic-gate if (s == -1) { 12980Sstevel@tonic-gate logperror("setup_rtsock: socket PF_ROUTE"); 12990Sstevel@tonic-gate exit(1); 13000Sstevel@tonic-gate } 13018485SPeter.Memishian@Sun.COM 13028485SPeter.Memishian@Sun.COM if (setsockopt(s, SOL_ROUTE, RT_AWARE, &aware, sizeof (aware)) == -1) { 13038485SPeter.Memishian@Sun.COM logperror("setup_rtsock: setsockopt RT_AWARE"); 13048485SPeter.Memishian@Sun.COM (void) close(s); 13058485SPeter.Memishian@Sun.COM exit(1); 13068485SPeter.Memishian@Sun.COM } 13078485SPeter.Memishian@Sun.COM 13080Sstevel@tonic-gate if ((flags = fcntl(s, F_GETFL, 0)) < 0) { 13090Sstevel@tonic-gate logperror("setup_rtsock: fcntl F_GETFL"); 13100Sstevel@tonic-gate (void) close(s); 13110Sstevel@tonic-gate exit(1); 13120Sstevel@tonic-gate } 13130Sstevel@tonic-gate if ((fcntl(s, F_SETFL, flags | O_NONBLOCK)) < 0) { 13140Sstevel@tonic-gate logperror("setup_rtsock: fcntl F_SETFL"); 13150Sstevel@tonic-gate (void) close(s); 13160Sstevel@tonic-gate exit(1); 13170Sstevel@tonic-gate } 13180Sstevel@tonic-gate if (poll_add(s) == -1) { 13190Sstevel@tonic-gate (void) close(s); 13200Sstevel@tonic-gate exit(1); 13210Sstevel@tonic-gate } 13220Sstevel@tonic-gate return (s); 13230Sstevel@tonic-gate } 13240Sstevel@tonic-gate 13250Sstevel@tonic-gate /* 13260Sstevel@tonic-gate * Process an RTM_IFINFO message received on a routing socket. 13270Sstevel@tonic-gate * The return value indicates whether a full interface scan is required. 13288485SPeter.Memishian@Sun.COM * Link up/down notifications are reflected in the IFF_RUNNING flag. 13290Sstevel@tonic-gate * If just the state of the IFF_RUNNING interface flag has changed, a 13300Sstevel@tonic-gate * a full interface scan isn't required. 13310Sstevel@tonic-gate */ 13320Sstevel@tonic-gate static boolean_t 13330Sstevel@tonic-gate process_rtm_ifinfo(if_msghdr_t *ifm, int type) 13340Sstevel@tonic-gate { 13350Sstevel@tonic-gate struct sockaddr_dl *sdl; 13360Sstevel@tonic-gate struct phyint *pi; 13370Sstevel@tonic-gate uint64_t old_flags; 13380Sstevel@tonic-gate struct phyint_instance *pii; 13390Sstevel@tonic-gate 13400Sstevel@tonic-gate assert(ifm->ifm_type == RTM_IFINFO && ifm->ifm_addrs == RTA_IFP); 13410Sstevel@tonic-gate 13420Sstevel@tonic-gate /* 13430Sstevel@tonic-gate * Although the sockaddr_dl structure is directly after the 13440Sstevel@tonic-gate * if_msghdr_t structure. At the time of writing, the size of the 13450Sstevel@tonic-gate * if_msghdr_t structure is different on 32 and 64 bit kernels, due 13460Sstevel@tonic-gate * to the presence of a timeval structure, which contains longs, 13470Sstevel@tonic-gate * in the if_data structure. Anyway, we know where the message ends, 13480Sstevel@tonic-gate * so we work backwards to get the start of the sockaddr_dl structure. 13490Sstevel@tonic-gate */ 13500Sstevel@tonic-gate /*LINTED*/ 13510Sstevel@tonic-gate sdl = (struct sockaddr_dl *)((char *)ifm + ifm->ifm_msglen - 13524770Smeem sizeof (struct sockaddr_dl)); 13530Sstevel@tonic-gate 13540Sstevel@tonic-gate assert(sdl->sdl_family == AF_LINK); 13550Sstevel@tonic-gate 13560Sstevel@tonic-gate /* 13570Sstevel@tonic-gate * The interface name is in sdl_data. 13580Sstevel@tonic-gate * RTM_IFINFO messages are only generated for logical interface 13590Sstevel@tonic-gate * zero, so there is no colon and logical interface number to 13600Sstevel@tonic-gate * strip from the name. The name is not null terminated, but 13610Sstevel@tonic-gate * there should be enough space in sdl_data to add the null. 13620Sstevel@tonic-gate */ 13630Sstevel@tonic-gate if (sdl->sdl_nlen >= sizeof (sdl->sdl_data)) { 13640Sstevel@tonic-gate if (debug & D_LINKNOTE) 13654770Smeem logdebug("process_rtm_ifinfo: phyint name too long\n"); 13660Sstevel@tonic-gate return (_B_TRUE); 13670Sstevel@tonic-gate } 13680Sstevel@tonic-gate sdl->sdl_data[sdl->sdl_nlen] = 0; 13690Sstevel@tonic-gate 13700Sstevel@tonic-gate pi = phyint_lookup(sdl->sdl_data); 13710Sstevel@tonic-gate if (pi == NULL) { 13720Sstevel@tonic-gate if (debug & D_LINKNOTE) 13730Sstevel@tonic-gate logdebug("process_rtm_ifinfo: phyint lookup failed" 13744770Smeem " for %s\n", sdl->sdl_data); 13750Sstevel@tonic-gate return (_B_TRUE); 13760Sstevel@tonic-gate } 13770Sstevel@tonic-gate 13780Sstevel@tonic-gate /* 13790Sstevel@tonic-gate * We want to try and avoid doing a full interface scan for 13808485SPeter.Memishian@Sun.COM * link state notifications from the datalink layer, as indicated 13810Sstevel@tonic-gate * by the state of the IFF_RUNNING flag. If just the 13820Sstevel@tonic-gate * IFF_RUNNING flag has changed state, the link state changes 13830Sstevel@tonic-gate * are processed without a full scan. 13840Sstevel@tonic-gate * If there is both an IPv4 and IPv6 instance associated with 13850Sstevel@tonic-gate * the physical interface, we will get an RTM_IFINFO message 13860Sstevel@tonic-gate * for each instance. If we just maintained a single copy of 13870Sstevel@tonic-gate * the physical interface flags, it would appear that no flags 13880Sstevel@tonic-gate * had changed when the second message is processed, leading us 13890Sstevel@tonic-gate * to believe that the message wasn't generated by a flags change, 13900Sstevel@tonic-gate * and that a full interface scan is required. 13910Sstevel@tonic-gate * To get around this problem, two additional copies of the flags 13920Sstevel@tonic-gate * are kept, one copy for each instance. These are only used in 13930Sstevel@tonic-gate * this routine. At any one time, all three copies of the flags 13940Sstevel@tonic-gate * should be identical except for the IFF_RUNNING flag. The 13950Sstevel@tonic-gate * copy of the flags in the "phyint" structure is always up to 13960Sstevel@tonic-gate * date. 13970Sstevel@tonic-gate */ 13980Sstevel@tonic-gate pii = (type == AF_INET) ? pi->pi_v4 : pi->pi_v6; 13990Sstevel@tonic-gate if (pii == NULL) { 14000Sstevel@tonic-gate if (debug & D_LINKNOTE) 14010Sstevel@tonic-gate logdebug("process_rtm_ifinfo: no instance of address " 14020Sstevel@tonic-gate "family %s for %s\n", AF_STR(type), pi->pi_name); 14030Sstevel@tonic-gate return (_B_TRUE); 14040Sstevel@tonic-gate } 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate old_flags = pii->pii_flags; 14070Sstevel@tonic-gate pii->pii_flags = PHYINT_FLAGS(ifm->ifm_flags); 14080Sstevel@tonic-gate pi->pi_flags = pii->pii_flags; 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate if (debug & D_LINKNOTE) { 14110Sstevel@tonic-gate logdebug("process_rtm_ifinfo: %s address family: %s, " 14120Sstevel@tonic-gate "old flags: %llx, new flags: %llx\n", pi->pi_name, 14130Sstevel@tonic-gate AF_STR(type), old_flags, pi->pi_flags); 14140Sstevel@tonic-gate } 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate /* 14170Sstevel@tonic-gate * If IFF_STANDBY has changed, indicate that the interface has changed 1418*10649SPeter.Memishian@Sun.COM * types and refresh IFF_INACTIVE if need be. 14190Sstevel@tonic-gate */ 1420*10649SPeter.Memishian@Sun.COM if ((old_flags ^ pii->pii_flags) & IFF_STANDBY) { 14218485SPeter.Memishian@Sun.COM phyint_changed(pi); 1422*10649SPeter.Memishian@Sun.COM if (pii->pii_flags & IFF_STANDBY) 1423*10649SPeter.Memishian@Sun.COM phyint_standby_refresh_inactive(pi); 1424*10649SPeter.Memishian@Sun.COM } 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate /* Has just the IFF_RUNNING flag changed state ? */ 14270Sstevel@tonic-gate if ((old_flags ^ pii->pii_flags) != IFF_RUNNING) { 14280Sstevel@tonic-gate struct phyint_instance *pii_other; 14290Sstevel@tonic-gate /* 14300Sstevel@tonic-gate * It wasn't just a link state change. Update 14310Sstevel@tonic-gate * the other instance's copy of the flags. 14320Sstevel@tonic-gate */ 14330Sstevel@tonic-gate pii_other = phyint_inst_other(pii); 14340Sstevel@tonic-gate if (pii_other != NULL) 14350Sstevel@tonic-gate pii_other->pii_flags = pii->pii_flags; 14360Sstevel@tonic-gate return (_B_TRUE); 14370Sstevel@tonic-gate } 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate return (_B_FALSE); 14400Sstevel@tonic-gate } 14410Sstevel@tonic-gate 14420Sstevel@tonic-gate /* 14430Sstevel@tonic-gate * Retrieve as many routing socket messages as possible, and try to 14440Sstevel@tonic-gate * empty the routing sockets. Initiate full scan of targets or interfaces 14450Sstevel@tonic-gate * as needed. 14460Sstevel@tonic-gate * We listen on separate IPv4 an IPv6 sockets so that we can accurately 14470Sstevel@tonic-gate * detect changes in certain flags (see "process_rtm_ifinfo()" above). 14480Sstevel@tonic-gate */ 14490Sstevel@tonic-gate static void 14500Sstevel@tonic-gate process_rtsock(int rtsock_v4, int rtsock_v6) 14510Sstevel@tonic-gate { 14520Sstevel@tonic-gate int nbytes; 14530Sstevel@tonic-gate int64_t msg[2048 / 8]; 14540Sstevel@tonic-gate struct rt_msghdr *rtm; 14550Sstevel@tonic-gate boolean_t need_if_scan = _B_FALSE; 14560Sstevel@tonic-gate boolean_t need_rt_scan = _B_FALSE; 14570Sstevel@tonic-gate boolean_t rtm_ifinfo_seen = _B_FALSE; 14580Sstevel@tonic-gate int type; 14590Sstevel@tonic-gate 14600Sstevel@tonic-gate /* Read as many messages as possible and try to empty the sockets */ 14610Sstevel@tonic-gate for (type = AF_INET; ; type = AF_INET6) { 14620Sstevel@tonic-gate for (;;) { 14630Sstevel@tonic-gate nbytes = read((type == AF_INET) ? rtsock_v4 : 14644770Smeem rtsock_v6, msg, sizeof (msg)); 14650Sstevel@tonic-gate if (nbytes <= 0) { 14660Sstevel@tonic-gate /* No more messages */ 14670Sstevel@tonic-gate break; 14680Sstevel@tonic-gate } 14690Sstevel@tonic-gate rtm = (struct rt_msghdr *)msg; 14700Sstevel@tonic-gate if (rtm->rtm_version != RTM_VERSION) { 14710Sstevel@tonic-gate logerr("process_rtsock: version %d " 14720Sstevel@tonic-gate "not understood\n", rtm->rtm_version); 14730Sstevel@tonic-gate break; 14740Sstevel@tonic-gate } 14750Sstevel@tonic-gate 14760Sstevel@tonic-gate if (debug & D_PHYINT) { 14770Sstevel@tonic-gate logdebug("process_rtsock: message %d\n", 14780Sstevel@tonic-gate rtm->rtm_type); 14790Sstevel@tonic-gate } 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate switch (rtm->rtm_type) { 14820Sstevel@tonic-gate case RTM_NEWADDR: 14830Sstevel@tonic-gate case RTM_DELADDR: 14840Sstevel@tonic-gate /* 14850Sstevel@tonic-gate * Some logical interface has changed, 14860Sstevel@tonic-gate * have to scan everything to determine 14870Sstevel@tonic-gate * what actually changed. 14880Sstevel@tonic-gate */ 14890Sstevel@tonic-gate need_if_scan = _B_TRUE; 14900Sstevel@tonic-gate break; 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate case RTM_IFINFO: 14930Sstevel@tonic-gate rtm_ifinfo_seen = _B_TRUE; 14944770Smeem need_if_scan |= process_rtm_ifinfo( 14954770Smeem (if_msghdr_t *)rtm, type); 14960Sstevel@tonic-gate break; 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate case RTM_ADD: 14990Sstevel@tonic-gate case RTM_DELETE: 15000Sstevel@tonic-gate case RTM_CHANGE: 15010Sstevel@tonic-gate case RTM_OLDADD: 15020Sstevel@tonic-gate case RTM_OLDDEL: 15030Sstevel@tonic-gate need_rt_scan = _B_TRUE; 15040Sstevel@tonic-gate break; 15050Sstevel@tonic-gate 15060Sstevel@tonic-gate default: 15070Sstevel@tonic-gate /* Not interesting */ 15080Sstevel@tonic-gate break; 15090Sstevel@tonic-gate } 15100Sstevel@tonic-gate } 15110Sstevel@tonic-gate if (type == AF_INET6) 15120Sstevel@tonic-gate break; 15130Sstevel@tonic-gate } 15140Sstevel@tonic-gate 15150Sstevel@tonic-gate if (need_if_scan) { 15160Sstevel@tonic-gate if (debug & D_LINKNOTE && rtm_ifinfo_seen) 15170Sstevel@tonic-gate logdebug("process_rtsock: synchronizing with kernel\n"); 15180Sstevel@tonic-gate initifs(); 15190Sstevel@tonic-gate } else if (rtm_ifinfo_seen) { 15200Sstevel@tonic-gate if (debug & D_LINKNOTE) 15210Sstevel@tonic-gate logdebug("process_rtsock: " 15220Sstevel@tonic-gate "link up/down notification(s) seen\n"); 15230Sstevel@tonic-gate process_link_state_changes(); 15240Sstevel@tonic-gate } 15250Sstevel@tonic-gate 15260Sstevel@tonic-gate if (need_rt_scan) 15270Sstevel@tonic-gate init_router_targets(); 15280Sstevel@tonic-gate } 15290Sstevel@tonic-gate 15300Sstevel@tonic-gate /* 15310Sstevel@tonic-gate * Look if the phyint instance or one of its logints have been removed from 15320Sstevel@tonic-gate * the kernel and take appropriate action. 15330Sstevel@tonic-gate * Uses {pii,li}_in_use. 15340Sstevel@tonic-gate */ 15350Sstevel@tonic-gate static void 15360Sstevel@tonic-gate check_if_removed(struct phyint_instance *pii) 15370Sstevel@tonic-gate { 15380Sstevel@tonic-gate struct logint *li; 15390Sstevel@tonic-gate struct logint *next_li; 15400Sstevel@tonic-gate 15410Sstevel@tonic-gate /* Detect phyints that have been removed from the kernel. */ 15420Sstevel@tonic-gate if (!pii->pii_in_use) { 15430Sstevel@tonic-gate logtrace("%s %s has been removed from kernel\n", 15440Sstevel@tonic-gate AF_STR(pii->pii_af), pii->pii_phyint->pi_name); 15450Sstevel@tonic-gate phyint_inst_delete(pii); 15460Sstevel@tonic-gate } else { 15470Sstevel@tonic-gate /* Detect logints that have been removed. */ 15480Sstevel@tonic-gate for (li = pii->pii_logint; li != NULL; li = next_li) { 15490Sstevel@tonic-gate next_li = li->li_next; 15500Sstevel@tonic-gate if (!li->li_in_use) { 15510Sstevel@tonic-gate logint_delete(li); 15520Sstevel@tonic-gate } 15530Sstevel@tonic-gate } 15540Sstevel@tonic-gate } 15550Sstevel@tonic-gate } 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate /* 15588865SJonathan.Anderson@Sun.COM * Parse the supplied mib2 information to extract the routing information 15598865SJonathan.Anderson@Sun.COM * table. Process the routing table to get the list of known onlink routers 15608865SJonathan.Anderson@Sun.COM * and update our database. These onlink routers will serve as probe 15618865SJonathan.Anderson@Sun.COM * targets. 15620Sstevel@tonic-gate */ 15638865SJonathan.Anderson@Sun.COM static void 15648865SJonathan.Anderson@Sun.COM update_router_list(mib_item_t *item) 15650Sstevel@tonic-gate { 15668865SJonathan.Anderson@Sun.COM for (; item != NULL; item = item->mi_next) { 15678865SJonathan.Anderson@Sun.COM if (item->mi_opthdr.name == 0) 15680Sstevel@tonic-gate continue; 15698865SJonathan.Anderson@Sun.COM if (item->mi_opthdr.level == MIB2_IP && 15708865SJonathan.Anderson@Sun.COM item->mi_opthdr.name == MIB2_IP_ROUTE) { 15718865SJonathan.Anderson@Sun.COM ire_process_v4((mib2_ipRouteEntry_t *)item->mi_valp, 15728865SJonathan.Anderson@Sun.COM item->mi_opthdr.len); 15738865SJonathan.Anderson@Sun.COM } else if (item->mi_opthdr.level == MIB2_IP6 && 15748865SJonathan.Anderson@Sun.COM item->mi_opthdr.name == MIB2_IP6_ROUTE) { 15758865SJonathan.Anderson@Sun.COM ire_process_v6((mib2_ipv6RouteEntry_t *)item->mi_valp, 15768865SJonathan.Anderson@Sun.COM item->mi_opthdr.len); 15770Sstevel@tonic-gate } 15780Sstevel@tonic-gate } 15790Sstevel@tonic-gate } 15800Sstevel@tonic-gate 15818485SPeter.Memishian@Sun.COM 15820Sstevel@tonic-gate /* 15838485SPeter.Memishian@Sun.COM * Convert octet `octp' to a phyint name and store in `ifname' 15848485SPeter.Memishian@Sun.COM */ 15858485SPeter.Memishian@Sun.COM static void 15868485SPeter.Memishian@Sun.COM oct2ifname(const Octet_t *octp, char *ifname, size_t ifsize) 15878485SPeter.Memishian@Sun.COM { 15888485SPeter.Memishian@Sun.COM char *cp; 15898485SPeter.Memishian@Sun.COM size_t len = MIN(octp->o_length, ifsize - 1); 15908485SPeter.Memishian@Sun.COM 15918485SPeter.Memishian@Sun.COM (void) strncpy(ifname, octp->o_bytes, len); 15928485SPeter.Memishian@Sun.COM ifname[len] = '\0'; 15938485SPeter.Memishian@Sun.COM 15948485SPeter.Memishian@Sun.COM if ((cp = strchr(ifname, IF_SEPARATOR)) != NULL) 15958485SPeter.Memishian@Sun.COM *cp = '\0'; 15968485SPeter.Memishian@Sun.COM } 15978485SPeter.Memishian@Sun.COM 15988485SPeter.Memishian@Sun.COM /* 15998485SPeter.Memishian@Sun.COM * Examine the IPv4 routing table `buf' for possible targets. For each 16008485SPeter.Memishian@Sun.COM * possible target, if it's on the same subnet an interface route, pass 16018485SPeter.Memishian@Sun.COM * it to router_add_common() for further consideration. 16020Sstevel@tonic-gate */ 16030Sstevel@tonic-gate static void 16040Sstevel@tonic-gate ire_process_v4(mib2_ipRouteEntry_t *buf, size_t len) 16050Sstevel@tonic-gate { 16068485SPeter.Memishian@Sun.COM char ifname[LIFNAMSIZ]; 16078485SPeter.Memishian@Sun.COM mib2_ipRouteEntry_t *rp, *rp1, *endp; 16088485SPeter.Memishian@Sun.COM struct in_addr nexthop_v4; 16098485SPeter.Memishian@Sun.COM struct in6_addr nexthop; 16100Sstevel@tonic-gate 16118865SJonathan.Anderson@Sun.COM if (debug & D_TARGET) 16128865SJonathan.Anderson@Sun.COM logdebug("ire_process_v4(len %d)\n", len); 16138865SJonathan.Anderson@Sun.COM 16140Sstevel@tonic-gate if (len == 0) 16150Sstevel@tonic-gate return; 16168865SJonathan.Anderson@Sun.COM 16178865SJonathan.Anderson@Sun.COM assert((len % ipRouteEntrySize) == 0); 16188865SJonathan.Anderson@Sun.COM endp = buf + (len / ipRouteEntrySize); 16190Sstevel@tonic-gate 16200Sstevel@tonic-gate /* 16218485SPeter.Memishian@Sun.COM * Scan the routing table entries for any IRE_OFFSUBNET entries, and 16228485SPeter.Memishian@Sun.COM * cross-reference them with the interface routes to determine if 16238485SPeter.Memishian@Sun.COM * they're possible probe targets. 16240Sstevel@tonic-gate */ 16250Sstevel@tonic-gate for (rp = buf; rp < endp; rp++) { 16260Sstevel@tonic-gate if (!(rp->ipRouteInfo.re_ire_type & IRE_OFFSUBNET)) 16270Sstevel@tonic-gate continue; 16280Sstevel@tonic-gate 16298485SPeter.Memishian@Sun.COM /* Get the nexthop address. */ 16300Sstevel@tonic-gate nexthop_v4.s_addr = rp->ipRouteNextHop; 16310Sstevel@tonic-gate 16320Sstevel@tonic-gate /* 16338485SPeter.Memishian@Sun.COM * Rescan the routing table looking for interface routes that 16348485SPeter.Memishian@Sun.COM * are on the same subnet, and try to add them. If they're 16358485SPeter.Memishian@Sun.COM * not relevant (e.g., the interface route isn't part of an 16368485SPeter.Memishian@Sun.COM * IPMP group, router_add_common() will discard). 16370Sstevel@tonic-gate */ 16380Sstevel@tonic-gate for (rp1 = buf; rp1 < endp; rp1++) { 16398485SPeter.Memishian@Sun.COM if (!(rp1->ipRouteInfo.re_ire_type & IRE_INTERFACE) || 16408485SPeter.Memishian@Sun.COM rp1->ipRouteIfIndex.o_length == 0) 16410Sstevel@tonic-gate continue; 16428485SPeter.Memishian@Sun.COM 16438485SPeter.Memishian@Sun.COM if ((rp1->ipRouteDest & rp1->ipRouteMask) != 16448485SPeter.Memishian@Sun.COM (nexthop_v4.s_addr & rp1->ipRouteMask)) 16458485SPeter.Memishian@Sun.COM continue; 16468485SPeter.Memishian@Sun.COM 16478485SPeter.Memishian@Sun.COM oct2ifname(&rp1->ipRouteIfIndex, ifname, LIFNAMSIZ); 16488485SPeter.Memishian@Sun.COM IN6_INADDR_TO_V4MAPPED(&nexthop_v4, &nexthop); 16498485SPeter.Memishian@Sun.COM router_add_common(AF_INET, ifname, nexthop); 16500Sstevel@tonic-gate } 16510Sstevel@tonic-gate } 16520Sstevel@tonic-gate } 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate void 16550Sstevel@tonic-gate router_add_common(int af, char *ifname, struct in6_addr nexthop) 16560Sstevel@tonic-gate { 16570Sstevel@tonic-gate struct phyint_instance *pii; 16580Sstevel@tonic-gate struct phyint *pi; 16590Sstevel@tonic-gate 16600Sstevel@tonic-gate if (debug & D_TARGET) 16610Sstevel@tonic-gate logdebug("router_add_common(%s %s)\n", AF_STR(af), ifname); 16620Sstevel@tonic-gate 16630Sstevel@tonic-gate /* 16640Sstevel@tonic-gate * Retrieve the phyint instance; bail if it's not known to us yet. 16650Sstevel@tonic-gate */ 16660Sstevel@tonic-gate pii = phyint_inst_lookup(af, ifname); 16670Sstevel@tonic-gate if (pii == NULL) 16680Sstevel@tonic-gate return; 16690Sstevel@tonic-gate 16700Sstevel@tonic-gate /* 16710Sstevel@tonic-gate * Don't use our own addresses as targets. 16720Sstevel@tonic-gate */ 16732250Srk129064 if (own_address(nexthop)) 16740Sstevel@tonic-gate return; 16750Sstevel@tonic-gate 16760Sstevel@tonic-gate /* 16770Sstevel@tonic-gate * If the phyint is part a named group, then add the address to all 16780Sstevel@tonic-gate * members of the group; note that this is suboptimal in the IPv4 case 16790Sstevel@tonic-gate * as it has already been added to all matching interfaces in 16800Sstevel@tonic-gate * ire_process_v4(). Otherwise, add the address only to the phyint 16810Sstevel@tonic-gate * itself, since other phyints in the anongroup may not be on the same 16820Sstevel@tonic-gate * subnet. 16830Sstevel@tonic-gate */ 16840Sstevel@tonic-gate pi = pii->pii_phyint; 16850Sstevel@tonic-gate if (pi->pi_group == phyint_anongroup) { 16860Sstevel@tonic-gate target_add(pii, nexthop, _B_TRUE); 16870Sstevel@tonic-gate } else { 16880Sstevel@tonic-gate pi = pi->pi_group->pg_phyint; 16890Sstevel@tonic-gate for (; pi != NULL; pi = pi->pi_pgnext) 16900Sstevel@tonic-gate target_add(PHYINT_INSTANCE(pi, af), nexthop, _B_TRUE); 16910Sstevel@tonic-gate } 16920Sstevel@tonic-gate } 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate /* 16958485SPeter.Memishian@Sun.COM * Examine the IPv6 routing table `buf' for possible link-local targets, and 16968485SPeter.Memishian@Sun.COM * pass any contenders to router_add_common() for further consideration. 16970Sstevel@tonic-gate */ 16980Sstevel@tonic-gate static void 16990Sstevel@tonic-gate ire_process_v6(mib2_ipv6RouteEntry_t *buf, size_t len) 17000Sstevel@tonic-gate { 17018485SPeter.Memishian@Sun.COM struct lifreq lifr; 17028485SPeter.Memishian@Sun.COM char ifname[LIFNAMSIZ]; 17038485SPeter.Memishian@Sun.COM char grname[LIFGRNAMSIZ]; 17048485SPeter.Memishian@Sun.COM mib2_ipv6RouteEntry_t *rp, *rp1, *endp; 17058485SPeter.Memishian@Sun.COM struct in6_addr nexthop_v6; 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate if (debug & D_TARGET) 17080Sstevel@tonic-gate logdebug("ire_process_v6(len %d)\n", len); 17090Sstevel@tonic-gate 17100Sstevel@tonic-gate if (len == 0) 17110Sstevel@tonic-gate return; 17120Sstevel@tonic-gate 17138865SJonathan.Anderson@Sun.COM assert((len % ipv6RouteEntrySize) == 0); 17148865SJonathan.Anderson@Sun.COM endp = buf + (len / ipv6RouteEntrySize); 17150Sstevel@tonic-gate 17160Sstevel@tonic-gate /* 17178485SPeter.Memishian@Sun.COM * Scan the routing table entries for any IRE_OFFSUBNET entries, and 17188485SPeter.Memishian@Sun.COM * cross-reference them with the interface routes to determine if 17198485SPeter.Memishian@Sun.COM * they're possible probe targets. 17200Sstevel@tonic-gate */ 17210Sstevel@tonic-gate for (rp = buf; rp < endp; rp++) { 17228485SPeter.Memishian@Sun.COM if (!(rp->ipv6RouteInfo.re_ire_type & IRE_OFFSUBNET) || 17238485SPeter.Memishian@Sun.COM !IN6_IS_ADDR_LINKLOCAL(&rp->ipv6RouteNextHop)) 17240Sstevel@tonic-gate continue; 17250Sstevel@tonic-gate 17268485SPeter.Memishian@Sun.COM /* Get the nexthop address. */ 17278485SPeter.Memishian@Sun.COM nexthop_v6 = rp->ipv6RouteNextHop; 17288485SPeter.Memishian@Sun.COM 17290Sstevel@tonic-gate /* 17308485SPeter.Memishian@Sun.COM * The interface name should always exist for link-locals; 17318485SPeter.Memishian@Sun.COM * we use it to map this entry to an IPMP group name. 17320Sstevel@tonic-gate */ 17338485SPeter.Memishian@Sun.COM if (rp->ipv6RouteIfIndex.o_length == 0) 17348485SPeter.Memishian@Sun.COM continue; 17358485SPeter.Memishian@Sun.COM 17368485SPeter.Memishian@Sun.COM oct2ifname(&rp->ipv6RouteIfIndex, lifr.lifr_name, LIFNAMSIZ); 17378485SPeter.Memishian@Sun.COM if (ioctl(ifsock_v6, SIOCGLIFGROUPNAME, &lifr) == -1 || 17388485SPeter.Memishian@Sun.COM strlcpy(grname, lifr.lifr_groupname, LIFGRNAMSIZ) == 0) { 17398485SPeter.Memishian@Sun.COM continue; 17408485SPeter.Memishian@Sun.COM } 17418485SPeter.Memishian@Sun.COM 17428485SPeter.Memishian@Sun.COM /* 17438485SPeter.Memishian@Sun.COM * Rescan the list of routes for interface routes, and add the 17448485SPeter.Memishian@Sun.COM * above target to any interfaces in the same IPMP group. 17458485SPeter.Memishian@Sun.COM */ 17468485SPeter.Memishian@Sun.COM for (rp1 = buf; rp1 < endp; rp1++) { 17478485SPeter.Memishian@Sun.COM if (!(rp1->ipv6RouteInfo.re_ire_type & IRE_INTERFACE) || 17488485SPeter.Memishian@Sun.COM rp1->ipv6RouteIfIndex.o_length == 0) { 17498485SPeter.Memishian@Sun.COM continue; 17508485SPeter.Memishian@Sun.COM } 17518485SPeter.Memishian@Sun.COM oct2ifname(&rp1->ipv6RouteIfIndex, ifname, LIFNAMSIZ); 17528485SPeter.Memishian@Sun.COM (void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ); 17538485SPeter.Memishian@Sun.COM 17548485SPeter.Memishian@Sun.COM if (ioctl(ifsock_v6, SIOCGLIFGROUPNAME, &lifr) != -1 && 17558485SPeter.Memishian@Sun.COM strcmp(lifr.lifr_groupname, grname) == 0) { 17568485SPeter.Memishian@Sun.COM router_add_common(AF_INET6, ifname, nexthop_v6); 17578485SPeter.Memishian@Sun.COM } 17580Sstevel@tonic-gate } 17590Sstevel@tonic-gate } 17600Sstevel@tonic-gate } 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate /* 17630Sstevel@tonic-gate * Build a list of target routers, by scanning the routing tables. 17640Sstevel@tonic-gate * It is assumed that interface routes exist, to reach the routers. 17650Sstevel@tonic-gate */ 17660Sstevel@tonic-gate static void 17670Sstevel@tonic-gate init_router_targets(void) 17680Sstevel@tonic-gate { 17690Sstevel@tonic-gate struct target *tg; 17700Sstevel@tonic-gate struct target *next_tg; 17710Sstevel@tonic-gate struct phyint_instance *pii; 17720Sstevel@tonic-gate struct phyint *pi; 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate if (force_mcast) 17750Sstevel@tonic-gate return; 17760Sstevel@tonic-gate 17770Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) { 17780Sstevel@tonic-gate pi = pii->pii_phyint; 17790Sstevel@tonic-gate /* 17808485SPeter.Memishian@Sun.COM * Set tg_in_use to false only for router targets. 17810Sstevel@tonic-gate */ 17828485SPeter.Memishian@Sun.COM if (!pii->pii_targets_are_routers) 17830Sstevel@tonic-gate continue; 17840Sstevel@tonic-gate 17850Sstevel@tonic-gate for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) 17860Sstevel@tonic-gate tg->tg_in_use = 0; 17870Sstevel@tonic-gate } 17880Sstevel@tonic-gate 17898865SJonathan.Anderson@Sun.COM if (mibwalk(update_router_list) == -1) 17908865SJonathan.Anderson@Sun.COM exit(1); 17910Sstevel@tonic-gate 17920Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) { 17938485SPeter.Memishian@Sun.COM pi = pii->pii_phyint; 17948485SPeter.Memishian@Sun.COM if (!pii->pii_targets_are_routers) 17950Sstevel@tonic-gate continue; 17960Sstevel@tonic-gate 17970Sstevel@tonic-gate for (tg = pii->pii_targets; tg != NULL; tg = next_tg) { 17980Sstevel@tonic-gate next_tg = tg->tg_next; 17998485SPeter.Memishian@Sun.COM /* 18008485SPeter.Memishian@Sun.COM * If the group has failed, it's likely the route was 18018485SPeter.Memishian@Sun.COM * removed by an application affected by that failure. 18028485SPeter.Memishian@Sun.COM * In that case, we keep the target so that we can 18038485SPeter.Memishian@Sun.COM * reliably repair, at which point we'll refresh the 18048485SPeter.Memishian@Sun.COM * target list again. 18058485SPeter.Memishian@Sun.COM */ 18068485SPeter.Memishian@Sun.COM if (!tg->tg_in_use && !GROUP_FAILED(pi->pi_group)) 18070Sstevel@tonic-gate target_delete(tg); 18080Sstevel@tonic-gate } 18090Sstevel@tonic-gate } 18100Sstevel@tonic-gate } 18110Sstevel@tonic-gate 18120Sstevel@tonic-gate /* 18130Sstevel@tonic-gate * Attempt to assign host targets to any interfaces that do not currently 18140Sstevel@tonic-gate * have probe targets by sharing targets with other interfaces in the group. 18150Sstevel@tonic-gate */ 18160Sstevel@tonic-gate static void 18170Sstevel@tonic-gate init_host_targets(void) 18180Sstevel@tonic-gate { 18190Sstevel@tonic-gate struct phyint_instance *pii; 18200Sstevel@tonic-gate struct phyint_group *pg; 18210Sstevel@tonic-gate 18220Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) { 18230Sstevel@tonic-gate pg = pii->pii_phyint->pi_group; 18240Sstevel@tonic-gate if (pg != phyint_anongroup && pii->pii_targets == NULL) 18250Sstevel@tonic-gate dup_host_targets(pii); 18260Sstevel@tonic-gate } 18270Sstevel@tonic-gate } 18280Sstevel@tonic-gate 18290Sstevel@tonic-gate /* 18300Sstevel@tonic-gate * Duplicate host targets from other phyints of the group to 18310Sstevel@tonic-gate * the phyint instance 'desired_pii'. 18320Sstevel@tonic-gate */ 18330Sstevel@tonic-gate static void 18340Sstevel@tonic-gate dup_host_targets(struct phyint_instance *desired_pii) 18350Sstevel@tonic-gate { 18360Sstevel@tonic-gate int af; 18370Sstevel@tonic-gate struct phyint *pi; 18380Sstevel@tonic-gate struct phyint_instance *pii; 18390Sstevel@tonic-gate struct target *tg; 18400Sstevel@tonic-gate 18410Sstevel@tonic-gate assert(desired_pii->pii_phyint->pi_group != phyint_anongroup); 18420Sstevel@tonic-gate 18430Sstevel@tonic-gate af = desired_pii->pii_af; 18440Sstevel@tonic-gate 18450Sstevel@tonic-gate /* 18460Sstevel@tonic-gate * For every phyint in the same group as desired_pii, check if 18470Sstevel@tonic-gate * it has any host targets. If so add them to desired_pii. 18480Sstevel@tonic-gate */ 18490Sstevel@tonic-gate for (pi = desired_pii->pii_phyint; pi != NULL; pi = pi->pi_pgnext) { 18500Sstevel@tonic-gate pii = PHYINT_INSTANCE(pi, af); 18510Sstevel@tonic-gate /* 18520Sstevel@tonic-gate * We know that we don't have targets on this phyint instance 18530Sstevel@tonic-gate * since we have been called. But we still check for 18540Sstevel@tonic-gate * pii_targets_are_routers because another phyint instance 18550Sstevel@tonic-gate * could have router targets, since IFF_NOFAILOVER addresses 18560Sstevel@tonic-gate * on different phyint instances may belong to different 18570Sstevel@tonic-gate * subnets. 18580Sstevel@tonic-gate */ 18590Sstevel@tonic-gate if ((pii == NULL) || (pii == desired_pii) || 18600Sstevel@tonic-gate pii->pii_targets_are_routers) 18610Sstevel@tonic-gate continue; 18620Sstevel@tonic-gate for (tg = pii->pii_targets; tg != NULL; tg = tg->tg_next) { 18630Sstevel@tonic-gate target_create(desired_pii, tg->tg_address, _B_FALSE); 18640Sstevel@tonic-gate } 18650Sstevel@tonic-gate } 18660Sstevel@tonic-gate } 18670Sstevel@tonic-gate 18680Sstevel@tonic-gate static void 18690Sstevel@tonic-gate usage(char *cmd) 18700Sstevel@tonic-gate { 18710Sstevel@tonic-gate (void) fprintf(stderr, "usage: %s\n", cmd); 18720Sstevel@tonic-gate } 18730Sstevel@tonic-gate 18740Sstevel@tonic-gate 18750Sstevel@tonic-gate #define MPATHD_DEFAULT_FILE "/etc/default/mpathd" 18760Sstevel@tonic-gate 18770Sstevel@tonic-gate /* Get an option from the /etc/default/mpathd file */ 18780Sstevel@tonic-gate static char * 18790Sstevel@tonic-gate getdefault(char *name) 18800Sstevel@tonic-gate { 18810Sstevel@tonic-gate char namebuf[BUFSIZ]; 18820Sstevel@tonic-gate char *value = NULL; 18830Sstevel@tonic-gate 18840Sstevel@tonic-gate if (defopen(MPATHD_DEFAULT_FILE) == 0) { 18850Sstevel@tonic-gate char *cp; 18860Sstevel@tonic-gate int flags; 18870Sstevel@tonic-gate 18880Sstevel@tonic-gate /* 18890Sstevel@tonic-gate * ignore case 18900Sstevel@tonic-gate */ 18910Sstevel@tonic-gate flags = defcntl(DC_GETFLAGS, 0); 18920Sstevel@tonic-gate TURNOFF(flags, DC_CASE); 18930Sstevel@tonic-gate (void) defcntl(DC_SETFLAGS, flags); 18940Sstevel@tonic-gate 18950Sstevel@tonic-gate /* Add "=" to the name */ 18960Sstevel@tonic-gate (void) strncpy(namebuf, name, sizeof (namebuf) - 2); 18970Sstevel@tonic-gate (void) strncat(namebuf, "=", 2); 18980Sstevel@tonic-gate 18990Sstevel@tonic-gate if ((cp = defread(namebuf)) != NULL) 19000Sstevel@tonic-gate value = strdup(cp); 19010Sstevel@tonic-gate 19020Sstevel@tonic-gate /* close */ 19030Sstevel@tonic-gate (void) defopen((char *)NULL); 19040Sstevel@tonic-gate } 19050Sstevel@tonic-gate return (value); 19060Sstevel@tonic-gate } 19070Sstevel@tonic-gate 19080Sstevel@tonic-gate 19090Sstevel@tonic-gate /* 19100Sstevel@tonic-gate * Command line options below 19110Sstevel@tonic-gate */ 19120Sstevel@tonic-gate boolean_t failback_enabled = _B_TRUE; /* failback enabled/disabled */ 19138485SPeter.Memishian@Sun.COM boolean_t track_all_phyints = _B_FALSE; /* track all IP interfaces */ 19140Sstevel@tonic-gate static boolean_t adopt = _B_FALSE; 19150Sstevel@tonic-gate static boolean_t foreground = _B_FALSE; 19160Sstevel@tonic-gate 19170Sstevel@tonic-gate int 19180Sstevel@tonic-gate main(int argc, char *argv[]) 19190Sstevel@tonic-gate { 19200Sstevel@tonic-gate int i; 19210Sstevel@tonic-gate int c; 19228485SPeter.Memishian@Sun.COM struct phyint *pi; 19230Sstevel@tonic-gate struct phyint_instance *pii; 19240Sstevel@tonic-gate char *value; 19250Sstevel@tonic-gate 19260Sstevel@tonic-gate argv0 = argv; /* Saved for re-exec on SIGHUP */ 19270Sstevel@tonic-gate srandom(gethostid()); /* Initialize the random number generator */ 19280Sstevel@tonic-gate 19290Sstevel@tonic-gate /* 19300Sstevel@tonic-gate * NOTE: The messages output by in.mpathd are not suitable for 19310Sstevel@tonic-gate * translation, so we do not call textdomain(). 19320Sstevel@tonic-gate */ 19330Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 19340Sstevel@tonic-gate 19350Sstevel@tonic-gate /* 19360Sstevel@tonic-gate * Get the user specified value of 'failure detection time' 19370Sstevel@tonic-gate * from /etc/default/mpathd 19380Sstevel@tonic-gate */ 19390Sstevel@tonic-gate value = getdefault("FAILURE_DETECTION_TIME"); 19400Sstevel@tonic-gate if (value != NULL) { 19410Sstevel@tonic-gate user_failure_detection_time = 19420Sstevel@tonic-gate (int)strtol((char *)value, NULL, 0); 19430Sstevel@tonic-gate 19440Sstevel@tonic-gate if (user_failure_detection_time <= 0) { 19450Sstevel@tonic-gate user_failure_detection_time = FAILURE_DETECTION_TIME; 19460Sstevel@tonic-gate logerr("Invalid failure detection time %s, assuming " 19478485SPeter.Memishian@Sun.COM "default of %d ms\n", value, 19488485SPeter.Memishian@Sun.COM user_failure_detection_time); 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate } else if (user_failure_detection_time < 19510Sstevel@tonic-gate MIN_FAILURE_DETECTION_TIME) { 19520Sstevel@tonic-gate user_failure_detection_time = 19530Sstevel@tonic-gate MIN_FAILURE_DETECTION_TIME; 19540Sstevel@tonic-gate logerr("Too small failure detection time of %s, " 19558485SPeter.Memishian@Sun.COM "assuming minimum of %d ms\n", value, 19560Sstevel@tonic-gate user_failure_detection_time); 19570Sstevel@tonic-gate } 19580Sstevel@tonic-gate free(value); 19590Sstevel@tonic-gate } else { 19600Sstevel@tonic-gate /* User has not specified the parameter, Use default value */ 19610Sstevel@tonic-gate user_failure_detection_time = FAILURE_DETECTION_TIME; 19620Sstevel@tonic-gate } 19630Sstevel@tonic-gate 19640Sstevel@tonic-gate /* 19650Sstevel@tonic-gate * This gives the frequency at which probes will be sent. 19660Sstevel@tonic-gate * When fdt ms elapses, we should be able to determine 19670Sstevel@tonic-gate * whether 5 consecutive probes have failed or not. 19680Sstevel@tonic-gate * 1 probe will be sent in every user_probe_interval ms, 19690Sstevel@tonic-gate * randomly anytime in the (0.5 - 1.0) 2nd half of every 19700Sstevel@tonic-gate * user_probe_interval. Thus when we send out probe 'n' we 19710Sstevel@tonic-gate * can be sure that probe 'n - 2' is lost, if we have not 19720Sstevel@tonic-gate * got the ack. (since the probe interval is > crtt). But 19730Sstevel@tonic-gate * probe 'n - 1' may be a valid unacked probe, since the 19740Sstevel@tonic-gate * time between 2 successive probes could be as small as 19750Sstevel@tonic-gate * 0.5 * user_probe_interval. Hence the NUM_PROBE_FAILS + 2 19760Sstevel@tonic-gate */ 19770Sstevel@tonic-gate user_probe_interval = user_failure_detection_time / 19780Sstevel@tonic-gate (NUM_PROBE_FAILS + 2); 19790Sstevel@tonic-gate 19800Sstevel@tonic-gate /* 19810Sstevel@tonic-gate * Get the user specified value of failback_enabled from 19820Sstevel@tonic-gate * /etc/default/mpathd 19830Sstevel@tonic-gate */ 19840Sstevel@tonic-gate value = getdefault("FAILBACK"); 19850Sstevel@tonic-gate if (value != NULL) { 19868485SPeter.Memishian@Sun.COM if (strcasecmp(value, "yes") == 0) 19870Sstevel@tonic-gate failback_enabled = _B_TRUE; 19888485SPeter.Memishian@Sun.COM else if (strcasecmp(value, "no") == 0) 19890Sstevel@tonic-gate failback_enabled = _B_FALSE; 19900Sstevel@tonic-gate else 19910Sstevel@tonic-gate logerr("Invalid value for FAILBACK %s\n", value); 19920Sstevel@tonic-gate free(value); 19930Sstevel@tonic-gate } else { 19940Sstevel@tonic-gate failback_enabled = _B_TRUE; 19950Sstevel@tonic-gate } 19960Sstevel@tonic-gate 19970Sstevel@tonic-gate /* 19980Sstevel@tonic-gate * Get the user specified value of track_all_phyints from 19990Sstevel@tonic-gate * /etc/default/mpathd. The sense is reversed in 20000Sstevel@tonic-gate * TRACK_INTERFACES_ONLY_WITH_GROUPS. 20010Sstevel@tonic-gate */ 20020Sstevel@tonic-gate value = getdefault("TRACK_INTERFACES_ONLY_WITH_GROUPS"); 20030Sstevel@tonic-gate if (value != NULL) { 20048485SPeter.Memishian@Sun.COM if (strcasecmp(value, "yes") == 0) 20050Sstevel@tonic-gate track_all_phyints = _B_FALSE; 20068485SPeter.Memishian@Sun.COM else if (strcasecmp(value, "no") == 0) 20070Sstevel@tonic-gate track_all_phyints = _B_TRUE; 20080Sstevel@tonic-gate else 20090Sstevel@tonic-gate logerr("Invalid value for " 20100Sstevel@tonic-gate "TRACK_INTERFACES_ONLY_WITH_GROUPS %s\n", value); 20110Sstevel@tonic-gate free(value); 20120Sstevel@tonic-gate } else { 20130Sstevel@tonic-gate track_all_phyints = _B_FALSE; 20140Sstevel@tonic-gate } 20150Sstevel@tonic-gate 20160Sstevel@tonic-gate while ((c = getopt(argc, argv, "adD:ml")) != EOF) { 20170Sstevel@tonic-gate switch (c) { 20180Sstevel@tonic-gate case 'a': 20190Sstevel@tonic-gate adopt = _B_TRUE; 20200Sstevel@tonic-gate break; 20210Sstevel@tonic-gate case 'm': 20220Sstevel@tonic-gate force_mcast = _B_TRUE; 20230Sstevel@tonic-gate break; 20240Sstevel@tonic-gate case 'd': 20250Sstevel@tonic-gate debug = D_ALL; 20260Sstevel@tonic-gate foreground = _B_TRUE; 20270Sstevel@tonic-gate break; 20280Sstevel@tonic-gate case 'D': 20290Sstevel@tonic-gate i = (int)strtol(optarg, NULL, 0); 20300Sstevel@tonic-gate if (i == 0) { 20310Sstevel@tonic-gate (void) fprintf(stderr, "Bad debug flags: %s\n", 20320Sstevel@tonic-gate optarg); 20330Sstevel@tonic-gate exit(1); 20340Sstevel@tonic-gate } 20350Sstevel@tonic-gate debug |= i; 20360Sstevel@tonic-gate foreground = _B_TRUE; 20370Sstevel@tonic-gate break; 20380Sstevel@tonic-gate case 'l': 20390Sstevel@tonic-gate /* 20400Sstevel@tonic-gate * Turn off link state notification handling. 20410Sstevel@tonic-gate * Undocumented command line flag, for debugging 20420Sstevel@tonic-gate * purposes. 20430Sstevel@tonic-gate */ 20440Sstevel@tonic-gate handle_link_notifications = _B_FALSE; 20450Sstevel@tonic-gate break; 20460Sstevel@tonic-gate default: 20470Sstevel@tonic-gate usage(argv[0]); 20480Sstevel@tonic-gate exit(1); 20490Sstevel@tonic-gate } 20500Sstevel@tonic-gate } 20510Sstevel@tonic-gate 20520Sstevel@tonic-gate /* 20530Sstevel@tonic-gate * The sockets for the loopback command interface should be listening 20540Sstevel@tonic-gate * before we fork and exit in daemonize(). This way, whoever started us 20550Sstevel@tonic-gate * can use the loopback interface as soon as they get a zero exit 20560Sstevel@tonic-gate * status. 20570Sstevel@tonic-gate */ 20580Sstevel@tonic-gate lsock_v4 = setup_listener(AF_INET); 20590Sstevel@tonic-gate lsock_v6 = setup_listener(AF_INET6); 20600Sstevel@tonic-gate 20610Sstevel@tonic-gate if (lsock_v4 < 0 && lsock_v6 < 0) { 20620Sstevel@tonic-gate logerr("main: setup_listener failed for both IPv4 and IPv6\n"); 20630Sstevel@tonic-gate exit(1); 20640Sstevel@tonic-gate } 20650Sstevel@tonic-gate 20660Sstevel@tonic-gate if (!foreground) { 20670Sstevel@tonic-gate if (!daemonize()) { 20680Sstevel@tonic-gate logerr("cannot daemonize\n"); 20690Sstevel@tonic-gate exit(EXIT_FAILURE); 20700Sstevel@tonic-gate } 20710Sstevel@tonic-gate initlog(); 20720Sstevel@tonic-gate } 20730Sstevel@tonic-gate 20740Sstevel@tonic-gate /* 20750Sstevel@tonic-gate * Initializations: 20760Sstevel@tonic-gate * 1. Create ifsock* sockets. These are used for performing SIOC* 20770Sstevel@tonic-gate * ioctls. We have 2 sockets 1 each for IPv4 and IPv6. 20780Sstevel@tonic-gate * 2. Initialize a pipe for handling/recording signal events. 20790Sstevel@tonic-gate * 3. Create the routing sockets, used for listening 20800Sstevel@tonic-gate * to routing / interface changes. 20810Sstevel@tonic-gate * 4. phyint_init() - Initialize physical interface state 20820Sstevel@tonic-gate * (in mpd_tables.c). Must be done before creating interfaces, 20830Sstevel@tonic-gate * which timer_init() does indirectly. 20848865SJonathan.Anderson@Sun.COM * 5. Query kernel for route entry sizes (v4 and v6). 20858865SJonathan.Anderson@Sun.COM * 6. timer_init() - Initialize timer related stuff 20868865SJonathan.Anderson@Sun.COM * 7. initifs() - Initialize our database of all known interfaces 20878865SJonathan.Anderson@Sun.COM * 8. init_router_targets() - Initialize our database of all known 20880Sstevel@tonic-gate * router targets. 20890Sstevel@tonic-gate */ 20900Sstevel@tonic-gate ifsock_v4 = socket(AF_INET, SOCK_DGRAM, 0); 20910Sstevel@tonic-gate if (ifsock_v4 < 0) { 20920Sstevel@tonic-gate logperror("main: IPv4 socket open"); 20930Sstevel@tonic-gate exit(1); 20940Sstevel@tonic-gate } 20950Sstevel@tonic-gate 20960Sstevel@tonic-gate ifsock_v6 = socket(AF_INET6, SOCK_DGRAM, 0); 20970Sstevel@tonic-gate if (ifsock_v6 < 0) { 20980Sstevel@tonic-gate logperror("main: IPv6 socket open"); 20990Sstevel@tonic-gate exit(1); 21000Sstevel@tonic-gate } 21010Sstevel@tonic-gate 21020Sstevel@tonic-gate setup_eventpipe(); 21030Sstevel@tonic-gate 21040Sstevel@tonic-gate rtsock_v4 = setup_rtsock(AF_INET); 21050Sstevel@tonic-gate rtsock_v6 = setup_rtsock(AF_INET6); 21060Sstevel@tonic-gate 21070Sstevel@tonic-gate if (phyint_init() == -1) { 21080Sstevel@tonic-gate logerr("cannot initialize physical interface structures"); 21090Sstevel@tonic-gate exit(1); 21100Sstevel@tonic-gate } 21110Sstevel@tonic-gate 21128865SJonathan.Anderson@Sun.COM if (mibwalk(mib_get_constants) == -1) 21138865SJonathan.Anderson@Sun.COM exit(1); 21148865SJonathan.Anderson@Sun.COM 21150Sstevel@tonic-gate timer_init(); 21160Sstevel@tonic-gate 21170Sstevel@tonic-gate initifs(); 21180Sstevel@tonic-gate 21190Sstevel@tonic-gate /* 21200Sstevel@tonic-gate * If we're operating in "adopt" mode and no interfaces need to be 21210Sstevel@tonic-gate * tracked, shut down (ifconfig(1M) will restart us on demand if 21220Sstevel@tonic-gate * interfaces are subsequently put into multipathing groups). 21230Sstevel@tonic-gate */ 21240Sstevel@tonic-gate if (adopt && phyint_instances == NULL) 21250Sstevel@tonic-gate exit(0); 21260Sstevel@tonic-gate 21270Sstevel@tonic-gate /* 21280Sstevel@tonic-gate * Main body. Keep listening for activity on any of the sockets 21290Sstevel@tonic-gate * that we are monitoring and take appropriate action as necessary. 21300Sstevel@tonic-gate * signals are also handled synchronously. 21310Sstevel@tonic-gate */ 21320Sstevel@tonic-gate for (;;) { 21330Sstevel@tonic-gate if (poll(pollfds, pollfd_num, -1) < 0) { 21340Sstevel@tonic-gate if (errno == EINTR) 21350Sstevel@tonic-gate continue; 21360Sstevel@tonic-gate logperror("main: poll"); 21370Sstevel@tonic-gate exit(1); 21380Sstevel@tonic-gate } 21390Sstevel@tonic-gate for (i = 0; i < pollfd_num; i++) { 21400Sstevel@tonic-gate if ((pollfds[i].fd == -1) || 21410Sstevel@tonic-gate !(pollfds[i].revents & POLLIN)) 21420Sstevel@tonic-gate continue; 21430Sstevel@tonic-gate if (pollfds[i].fd == eventpipe_read) { 21440Sstevel@tonic-gate in_signal(eventpipe_read); 21450Sstevel@tonic-gate break; 21460Sstevel@tonic-gate } 21470Sstevel@tonic-gate if (pollfds[i].fd == rtsock_v4 || 21482496Smeem pollfds[i].fd == rtsock_v6) { 21490Sstevel@tonic-gate process_rtsock(rtsock_v4, rtsock_v6); 21500Sstevel@tonic-gate break; 21510Sstevel@tonic-gate } 21528485SPeter.Memishian@Sun.COM 21530Sstevel@tonic-gate for (pii = phyint_instances; pii != NULL; 21540Sstevel@tonic-gate pii = pii->pii_next) { 21550Sstevel@tonic-gate if (pollfds[i].fd == pii->pii_probe_sock) { 21560Sstevel@tonic-gate if (pii->pii_af == AF_INET) 21570Sstevel@tonic-gate in_data(pii); 21580Sstevel@tonic-gate else 21590Sstevel@tonic-gate in6_data(pii); 21600Sstevel@tonic-gate break; 21610Sstevel@tonic-gate } 21620Sstevel@tonic-gate } 21638485SPeter.Memishian@Sun.COM 21648485SPeter.Memishian@Sun.COM for (pi = phyints; pi != NULL; pi = pi->pi_next) { 21658485SPeter.Memishian@Sun.COM if (pi->pi_notes != 0 && 21668485SPeter.Memishian@Sun.COM pollfds[i].fd == dlpi_fd(pi->pi_dh)) { 21678485SPeter.Memishian@Sun.COM (void) dlpi_recv(pi->pi_dh, NULL, NULL, 21688485SPeter.Memishian@Sun.COM NULL, NULL, 0, NULL); 21698485SPeter.Memishian@Sun.COM break; 21708485SPeter.Memishian@Sun.COM } 21718485SPeter.Memishian@Sun.COM } 21728485SPeter.Memishian@Sun.COM 21730Sstevel@tonic-gate if (pollfds[i].fd == lsock_v4) 21740Sstevel@tonic-gate loopback_cmd(lsock_v4, AF_INET); 21750Sstevel@tonic-gate else if (pollfds[i].fd == lsock_v6) 21760Sstevel@tonic-gate loopback_cmd(lsock_v6, AF_INET6); 21770Sstevel@tonic-gate } 21780Sstevel@tonic-gate } 21790Sstevel@tonic-gate /* NOTREACHED */ 21800Sstevel@tonic-gate return (EXIT_SUCCESS); 21810Sstevel@tonic-gate } 21820Sstevel@tonic-gate 21830Sstevel@tonic-gate static int 21840Sstevel@tonic-gate setup_listener(int af) 21850Sstevel@tonic-gate { 21860Sstevel@tonic-gate int sock; 21870Sstevel@tonic-gate int on; 21880Sstevel@tonic-gate int len; 21890Sstevel@tonic-gate int ret; 21900Sstevel@tonic-gate struct sockaddr_storage laddr; 21910Sstevel@tonic-gate struct sockaddr_in *sin; 21920Sstevel@tonic-gate struct sockaddr_in6 *sin6; 21930Sstevel@tonic-gate struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; 21940Sstevel@tonic-gate 21950Sstevel@tonic-gate assert(af == AF_INET || af == AF_INET6); 21960Sstevel@tonic-gate 21970Sstevel@tonic-gate sock = socket(af, SOCK_STREAM, 0); 21980Sstevel@tonic-gate if (sock < 0) { 21990Sstevel@tonic-gate logperror("setup_listener: socket"); 22000Sstevel@tonic-gate exit(1); 22010Sstevel@tonic-gate } 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate on = 1; 22040Sstevel@tonic-gate if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, 22050Sstevel@tonic-gate sizeof (on)) < 0) { 22060Sstevel@tonic-gate logperror("setup_listener: setsockopt (SO_REUSEADDR)"); 22070Sstevel@tonic-gate exit(1); 22080Sstevel@tonic-gate } 22090Sstevel@tonic-gate 22100Sstevel@tonic-gate bzero(&laddr, sizeof (laddr)); 22110Sstevel@tonic-gate laddr.ss_family = af; 22120Sstevel@tonic-gate 22130Sstevel@tonic-gate if (af == AF_INET) { 22140Sstevel@tonic-gate sin = (struct sockaddr_in *)&laddr; 22150Sstevel@tonic-gate sin->sin_port = htons(MPATHD_PORT); 22160Sstevel@tonic-gate sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 22170Sstevel@tonic-gate len = sizeof (struct sockaddr_in); 22180Sstevel@tonic-gate } else { 22190Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&laddr; 22200Sstevel@tonic-gate sin6->sin6_port = htons(MPATHD_PORT); 22210Sstevel@tonic-gate sin6->sin6_addr = loopback_addr; 22220Sstevel@tonic-gate len = sizeof (struct sockaddr_in6); 22230Sstevel@tonic-gate } 22240Sstevel@tonic-gate 22250Sstevel@tonic-gate ret = bind(sock, (struct sockaddr *)&laddr, len); 22260Sstevel@tonic-gate if (ret < 0) { 22270Sstevel@tonic-gate if (errno == EADDRINUSE) { 22280Sstevel@tonic-gate /* 22290Sstevel@tonic-gate * Another instance of mpathd may be already active. 22300Sstevel@tonic-gate */ 22310Sstevel@tonic-gate logerr("main: is another instance of in.mpathd " 22320Sstevel@tonic-gate "already active?\n"); 22330Sstevel@tonic-gate exit(1); 22340Sstevel@tonic-gate } else { 22350Sstevel@tonic-gate (void) close(sock); 22360Sstevel@tonic-gate return (-1); 22370Sstevel@tonic-gate } 22380Sstevel@tonic-gate } 22390Sstevel@tonic-gate if (listen(sock, 30) < 0) { 22400Sstevel@tonic-gate logperror("main: listen"); 22410Sstevel@tonic-gate exit(1); 22420Sstevel@tonic-gate } 22430Sstevel@tonic-gate if (poll_add(sock) == -1) { 22440Sstevel@tonic-gate (void) close(sock); 22450Sstevel@tonic-gate exit(1); 22460Sstevel@tonic-gate } 22470Sstevel@tonic-gate 22480Sstevel@tonic-gate return (sock); 22490Sstevel@tonic-gate } 22500Sstevel@tonic-gate 22510Sstevel@tonic-gate /* 22520Sstevel@tonic-gate * Table of commands and their expected size; used by loopback_cmd(). 22530Sstevel@tonic-gate */ 22540Sstevel@tonic-gate static struct { 22550Sstevel@tonic-gate const char *name; 22560Sstevel@tonic-gate unsigned int size; 22570Sstevel@tonic-gate } commands[] = { 22580Sstevel@tonic-gate { "MI_PING", sizeof (uint32_t) }, 22590Sstevel@tonic-gate { "MI_OFFLINE", sizeof (mi_offline_t) }, 22600Sstevel@tonic-gate { "MI_UNDO_OFFLINE", sizeof (mi_undo_offline_t) }, 22610Sstevel@tonic-gate { "MI_QUERY", sizeof (mi_query_t) } 22620Sstevel@tonic-gate }; 22630Sstevel@tonic-gate 22640Sstevel@tonic-gate /* 22658485SPeter.Memishian@Sun.COM * Commands received over the loopback interface come here (via libipmp). 22660Sstevel@tonic-gate */ 22670Sstevel@tonic-gate static void 22680Sstevel@tonic-gate loopback_cmd(int sock, int family) 22690Sstevel@tonic-gate { 22700Sstevel@tonic-gate int newfd; 22710Sstevel@tonic-gate ssize_t len; 22728485SPeter.Memishian@Sun.COM boolean_t is_priv = _B_FALSE; 22730Sstevel@tonic-gate struct sockaddr_storage peer; 22740Sstevel@tonic-gate struct sockaddr_in *peer_sin; 22750Sstevel@tonic-gate struct sockaddr_in6 *peer_sin6; 22760Sstevel@tonic-gate socklen_t peerlen; 22770Sstevel@tonic-gate union mi_commands mpi; 22780Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 22790Sstevel@tonic-gate uint_t cmd; 22800Sstevel@tonic-gate int retval; 22810Sstevel@tonic-gate 22820Sstevel@tonic-gate peerlen = sizeof (peer); 22830Sstevel@tonic-gate newfd = accept(sock, (struct sockaddr *)&peer, &peerlen); 22840Sstevel@tonic-gate if (newfd < 0) { 22850Sstevel@tonic-gate logperror("loopback_cmd: accept"); 22860Sstevel@tonic-gate return; 22870Sstevel@tonic-gate } 22880Sstevel@tonic-gate 22890Sstevel@tonic-gate switch (family) { 22900Sstevel@tonic-gate case AF_INET: 22910Sstevel@tonic-gate /* 22920Sstevel@tonic-gate * Validate the address and port to make sure that 22930Sstevel@tonic-gate * non privileged processes don't connect and start 22940Sstevel@tonic-gate * talking to us. 22950Sstevel@tonic-gate */ 22960Sstevel@tonic-gate if (peerlen != sizeof (struct sockaddr_in)) { 22970Sstevel@tonic-gate logerr("loopback_cmd: AF_INET peerlen %d\n", peerlen); 22980Sstevel@tonic-gate (void) close(newfd); 22990Sstevel@tonic-gate return; 23000Sstevel@tonic-gate } 23010Sstevel@tonic-gate peer_sin = (struct sockaddr_in *)&peer; 23028485SPeter.Memishian@Sun.COM is_priv = ntohs(peer_sin->sin_port) < IPPORT_RESERVED; 23038485SPeter.Memishian@Sun.COM (void) inet_ntop(AF_INET, &peer_sin->sin_addr.s_addr, 23048485SPeter.Memishian@Sun.COM abuf, sizeof (abuf)); 23058485SPeter.Memishian@Sun.COM 23068485SPeter.Memishian@Sun.COM if (ntohl(peer_sin->sin_addr.s_addr) != INADDR_LOOPBACK) { 23070Sstevel@tonic-gate logerr("Attempt to connect from addr %s port %d\n", 23080Sstevel@tonic-gate abuf, ntohs(peer_sin->sin_port)); 23090Sstevel@tonic-gate (void) close(newfd); 23100Sstevel@tonic-gate return; 23110Sstevel@tonic-gate } 23120Sstevel@tonic-gate break; 23130Sstevel@tonic-gate 23140Sstevel@tonic-gate case AF_INET6: 23150Sstevel@tonic-gate if (peerlen != sizeof (struct sockaddr_in6)) { 23160Sstevel@tonic-gate logerr("loopback_cmd: AF_INET6 peerlen %d\n", peerlen); 23170Sstevel@tonic-gate (void) close(newfd); 23180Sstevel@tonic-gate return; 23190Sstevel@tonic-gate } 23200Sstevel@tonic-gate /* 23210Sstevel@tonic-gate * Validate the address and port to make sure that 23220Sstevel@tonic-gate * non privileged processes don't connect and start 23230Sstevel@tonic-gate * talking to us. 23240Sstevel@tonic-gate */ 23250Sstevel@tonic-gate peer_sin6 = (struct sockaddr_in6 *)&peer; 23268485SPeter.Memishian@Sun.COM is_priv = ntohs(peer_sin6->sin6_port) < IPPORT_RESERVED; 23278485SPeter.Memishian@Sun.COM (void) inet_ntop(AF_INET6, &peer_sin6->sin6_addr, abuf, 23288485SPeter.Memishian@Sun.COM sizeof (abuf)); 23298485SPeter.Memishian@Sun.COM if (!IN6_IS_ADDR_LOOPBACK(&peer_sin6->sin6_addr)) { 23300Sstevel@tonic-gate logerr("Attempt to connect from addr %s port %d\n", 23310Sstevel@tonic-gate abuf, ntohs(peer_sin6->sin6_port)); 23320Sstevel@tonic-gate (void) close(newfd); 23330Sstevel@tonic-gate return; 23340Sstevel@tonic-gate } 23350Sstevel@tonic-gate 23360Sstevel@tonic-gate default: 23370Sstevel@tonic-gate logdebug("loopback_cmd: family %d\n", family); 23380Sstevel@tonic-gate (void) close(newfd); 23390Sstevel@tonic-gate return; 23400Sstevel@tonic-gate } 23410Sstevel@tonic-gate 23420Sstevel@tonic-gate /* 23430Sstevel@tonic-gate * The sizeof the 'mpi' buffer corresponds to the maximum size of 23440Sstevel@tonic-gate * all supported commands 23450Sstevel@tonic-gate */ 23460Sstevel@tonic-gate len = read(newfd, &mpi, sizeof (mpi)); 23470Sstevel@tonic-gate 23480Sstevel@tonic-gate /* 23490Sstevel@tonic-gate * In theory, we can receive any sized message for a stream socket, 23500Sstevel@tonic-gate * but we don't expect that to happen for a small message over a 23510Sstevel@tonic-gate * loopback connection. 23520Sstevel@tonic-gate */ 23530Sstevel@tonic-gate if (len < sizeof (uint32_t)) { 23540Sstevel@tonic-gate logerr("loopback_cmd: bad command format or read returns " 23550Sstevel@tonic-gate "partial data %d\n", len); 23568485SPeter.Memishian@Sun.COM (void) close(newfd); 23578485SPeter.Memishian@Sun.COM return; 23580Sstevel@tonic-gate } 23590Sstevel@tonic-gate 23600Sstevel@tonic-gate cmd = mpi.mi_command; 23610Sstevel@tonic-gate if (cmd >= MI_NCMD) { 23620Sstevel@tonic-gate logerr("loopback_cmd: unknown command id `%d'\n", cmd); 23630Sstevel@tonic-gate (void) close(newfd); 23640Sstevel@tonic-gate return; 23650Sstevel@tonic-gate } 23660Sstevel@tonic-gate 23678485SPeter.Memishian@Sun.COM /* 23688485SPeter.Memishian@Sun.COM * Only MI_PING and MI_QUERY can come from unprivileged sources. 23698485SPeter.Memishian@Sun.COM */ 23708485SPeter.Memishian@Sun.COM if (!is_priv && (cmd != MI_QUERY && cmd != MI_PING)) { 23718485SPeter.Memishian@Sun.COM logerr("Unprivileged request from %s for privileged " 23728485SPeter.Memishian@Sun.COM "command %s\n", abuf, commands[cmd].name); 23738485SPeter.Memishian@Sun.COM (void) close(newfd); 23748485SPeter.Memishian@Sun.COM return; 23758485SPeter.Memishian@Sun.COM } 23768485SPeter.Memishian@Sun.COM 23770Sstevel@tonic-gate if (len < commands[cmd].size) { 23780Sstevel@tonic-gate logerr("loopback_cmd: short %s command (expected %d, got %d)\n", 23790Sstevel@tonic-gate commands[cmd].name, commands[cmd].size, len); 23800Sstevel@tonic-gate (void) close(newfd); 23810Sstevel@tonic-gate return; 23820Sstevel@tonic-gate } 23830Sstevel@tonic-gate 23840Sstevel@tonic-gate retval = process_cmd(newfd, &mpi); 23850Sstevel@tonic-gate if (retval != IPMP_SUCCESS) { 23860Sstevel@tonic-gate logerr("failed processing %s: %s\n", commands[cmd].name, 23870Sstevel@tonic-gate ipmp_errmsg(retval)); 23880Sstevel@tonic-gate } 23890Sstevel@tonic-gate (void) close(newfd); 23900Sstevel@tonic-gate } 23910Sstevel@tonic-gate 23920Sstevel@tonic-gate /* 23938485SPeter.Memishian@Sun.COM * Process the commands received via libipmp. 23940Sstevel@tonic-gate */ 23950Sstevel@tonic-gate static unsigned int 23960Sstevel@tonic-gate process_cmd(int newfd, union mi_commands *mpi) 23970Sstevel@tonic-gate { 23980Sstevel@tonic-gate struct phyint *pi; 23990Sstevel@tonic-gate struct mi_offline *mio; 24000Sstevel@tonic-gate struct mi_undo_offline *miu; 24018485SPeter.Memishian@Sun.COM unsigned int retval; 24028485SPeter.Memishian@Sun.COM 24038485SPeter.Memishian@Sun.COM switch (mpi->mi_command) { 24048485SPeter.Memishian@Sun.COM case MI_PING: 24058485SPeter.Memishian@Sun.COM return (send_result(newfd, IPMP_SUCCESS, 0)); 24068485SPeter.Memishian@Sun.COM 24070Sstevel@tonic-gate case MI_OFFLINE: 24080Sstevel@tonic-gate mio = &mpi->mi_ocmd; 24098485SPeter.Memishian@Sun.COM 24100Sstevel@tonic-gate pi = phyint_lookup(mio->mio_ifname); 24110Sstevel@tonic-gate if (pi == NULL) 24128485SPeter.Memishian@Sun.COM return (send_result(newfd, IPMP_EUNKIF, 0)); 24138485SPeter.Memishian@Sun.COM 24148485SPeter.Memishian@Sun.COM retval = phyint_offline(pi, mio->mio_min_redundancy); 24158485SPeter.Memishian@Sun.COM if (retval == IPMP_FAILURE) 24160Sstevel@tonic-gate return (send_result(newfd, IPMP_FAILURE, errno)); 24178485SPeter.Memishian@Sun.COM 24188485SPeter.Memishian@Sun.COM return (send_result(newfd, retval, 0)); 24190Sstevel@tonic-gate 24200Sstevel@tonic-gate case MI_UNDO_OFFLINE: 24210Sstevel@tonic-gate miu = &mpi->mi_ucmd; 24228485SPeter.Memishian@Sun.COM 24230Sstevel@tonic-gate pi = phyint_lookup(miu->miu_ifname); 24248485SPeter.Memishian@Sun.COM if (pi == NULL) 24258485SPeter.Memishian@Sun.COM return (send_result(newfd, IPMP_EUNKIF, 0)); 24268485SPeter.Memishian@Sun.COM 24278485SPeter.Memishian@Sun.COM retval = phyint_undo_offline(pi); 24288485SPeter.Memishian@Sun.COM if (retval == IPMP_FAILURE) 24290Sstevel@tonic-gate return (send_result(newfd, IPMP_FAILURE, errno)); 24300Sstevel@tonic-gate 24318485SPeter.Memishian@Sun.COM return (send_result(newfd, retval, 0)); 24320Sstevel@tonic-gate 24330Sstevel@tonic-gate case MI_QUERY: 24340Sstevel@tonic-gate return (process_query(newfd, &mpi->mi_qcmd)); 24350Sstevel@tonic-gate 24360Sstevel@tonic-gate default: 24370Sstevel@tonic-gate break; 24380Sstevel@tonic-gate } 24390Sstevel@tonic-gate 24400Sstevel@tonic-gate return (send_result(newfd, IPMP_EPROTO, 0)); 24410Sstevel@tonic-gate } 24420Sstevel@tonic-gate 24430Sstevel@tonic-gate /* 24440Sstevel@tonic-gate * Process the query request pointed to by `miq' and send a reply on file 24450Sstevel@tonic-gate * descriptor `fd'. Returns an IPMP error code. 24460Sstevel@tonic-gate */ 24470Sstevel@tonic-gate static unsigned int 24480Sstevel@tonic-gate process_query(int fd, mi_query_t *miq) 24490Sstevel@tonic-gate { 24508485SPeter.Memishian@Sun.COM ipmp_addrinfo_t *adinfop; 24518485SPeter.Memishian@Sun.COM ipmp_addrinfolist_t *adlp; 24520Sstevel@tonic-gate ipmp_groupinfo_t *grinfop; 24530Sstevel@tonic-gate ipmp_groupinfolist_t *grlp; 24540Sstevel@tonic-gate ipmp_grouplist_t *grlistp; 24550Sstevel@tonic-gate ipmp_ifinfo_t *ifinfop; 24560Sstevel@tonic-gate ipmp_ifinfolist_t *iflp; 24570Sstevel@tonic-gate ipmp_snap_t *snap; 24580Sstevel@tonic-gate unsigned int retval; 24590Sstevel@tonic-gate 24600Sstevel@tonic-gate switch (miq->miq_inforeq) { 24618485SPeter.Memishian@Sun.COM case IPMP_ADDRINFO: 24628485SPeter.Memishian@Sun.COM retval = getgraddrinfo(miq->miq_grname, &miq->miq_addr, 24638485SPeter.Memishian@Sun.COM &adinfop); 24648485SPeter.Memishian@Sun.COM if (retval != IPMP_SUCCESS) 24658485SPeter.Memishian@Sun.COM return (send_result(fd, retval, errno)); 24668485SPeter.Memishian@Sun.COM 24678485SPeter.Memishian@Sun.COM retval = send_result(fd, IPMP_SUCCESS, 0); 24688485SPeter.Memishian@Sun.COM if (retval == IPMP_SUCCESS) 24698485SPeter.Memishian@Sun.COM retval = send_addrinfo(fd, adinfop); 24708485SPeter.Memishian@Sun.COM 24718485SPeter.Memishian@Sun.COM ipmp_freeaddrinfo(adinfop); 24728485SPeter.Memishian@Sun.COM return (retval); 24738485SPeter.Memishian@Sun.COM 24740Sstevel@tonic-gate case IPMP_GROUPLIST: 24750Sstevel@tonic-gate retval = getgrouplist(&grlistp); 24760Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 24770Sstevel@tonic-gate return (send_result(fd, retval, errno)); 24780Sstevel@tonic-gate 24790Sstevel@tonic-gate retval = send_result(fd, IPMP_SUCCESS, 0); 24800Sstevel@tonic-gate if (retval == IPMP_SUCCESS) 24810Sstevel@tonic-gate retval = send_grouplist(fd, grlistp); 24820Sstevel@tonic-gate 24830Sstevel@tonic-gate ipmp_freegrouplist(grlistp); 24840Sstevel@tonic-gate return (retval); 24850Sstevel@tonic-gate 24860Sstevel@tonic-gate case IPMP_GROUPINFO: 24870Sstevel@tonic-gate miq->miq_grname[LIFGRNAMSIZ - 1] = '\0'; 24888485SPeter.Memishian@Sun.COM retval = getgroupinfo(miq->miq_grname, &grinfop); 24890Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 24900Sstevel@tonic-gate return (send_result(fd, retval, errno)); 24910Sstevel@tonic-gate 24920Sstevel@tonic-gate retval = send_result(fd, IPMP_SUCCESS, 0); 24930Sstevel@tonic-gate if (retval == IPMP_SUCCESS) 24940Sstevel@tonic-gate retval = send_groupinfo(fd, grinfop); 24950Sstevel@tonic-gate 24960Sstevel@tonic-gate ipmp_freegroupinfo(grinfop); 24970Sstevel@tonic-gate return (retval); 24980Sstevel@tonic-gate 24990Sstevel@tonic-gate case IPMP_IFINFO: 25000Sstevel@tonic-gate miq->miq_ifname[LIFNAMSIZ - 1] = '\0'; 25010Sstevel@tonic-gate retval = getifinfo(miq->miq_ifname, &ifinfop); 25020Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25030Sstevel@tonic-gate return (send_result(fd, retval, errno)); 25040Sstevel@tonic-gate 25050Sstevel@tonic-gate retval = send_result(fd, IPMP_SUCCESS, 0); 25060Sstevel@tonic-gate if (retval == IPMP_SUCCESS) 25070Sstevel@tonic-gate retval = send_ifinfo(fd, ifinfop); 25080Sstevel@tonic-gate 25090Sstevel@tonic-gate ipmp_freeifinfo(ifinfop); 25100Sstevel@tonic-gate return (retval); 25110Sstevel@tonic-gate 25120Sstevel@tonic-gate case IPMP_SNAP: 25138485SPeter.Memishian@Sun.COM /* 25148485SPeter.Memishian@Sun.COM * Before taking the snapshot, sync with the kernel. 25158485SPeter.Memishian@Sun.COM */ 25168485SPeter.Memishian@Sun.COM initifs(); 25178485SPeter.Memishian@Sun.COM 25180Sstevel@tonic-gate retval = getsnap(&snap); 25190Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25200Sstevel@tonic-gate return (send_result(fd, retval, errno)); 25210Sstevel@tonic-gate 25220Sstevel@tonic-gate retval = send_result(fd, IPMP_SUCCESS, 0); 25230Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25240Sstevel@tonic-gate goto out; 25250Sstevel@tonic-gate 25260Sstevel@tonic-gate retval = ipmp_writetlv(fd, IPMP_SNAP, sizeof (*snap), snap); 25270Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25280Sstevel@tonic-gate goto out; 25290Sstevel@tonic-gate 25300Sstevel@tonic-gate retval = send_grouplist(fd, snap->sn_grlistp); 25310Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25320Sstevel@tonic-gate goto out; 25330Sstevel@tonic-gate 25340Sstevel@tonic-gate iflp = snap->sn_ifinfolistp; 25350Sstevel@tonic-gate for (; iflp != NULL; iflp = iflp->ifl_next) { 25360Sstevel@tonic-gate retval = send_ifinfo(fd, iflp->ifl_ifinfop); 25370Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25380Sstevel@tonic-gate goto out; 25390Sstevel@tonic-gate } 25400Sstevel@tonic-gate 25410Sstevel@tonic-gate grlp = snap->sn_grinfolistp; 25420Sstevel@tonic-gate for (; grlp != NULL; grlp = grlp->grl_next) { 25430Sstevel@tonic-gate retval = send_groupinfo(fd, grlp->grl_grinfop); 25440Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25450Sstevel@tonic-gate goto out; 25460Sstevel@tonic-gate } 25478485SPeter.Memishian@Sun.COM 25488485SPeter.Memishian@Sun.COM adlp = snap->sn_adinfolistp; 25498485SPeter.Memishian@Sun.COM for (; adlp != NULL; adlp = adlp->adl_next) { 25508485SPeter.Memishian@Sun.COM retval = send_addrinfo(fd, adlp->adl_adinfop); 25518485SPeter.Memishian@Sun.COM if (retval != IPMP_SUCCESS) 25528485SPeter.Memishian@Sun.COM goto out; 25538485SPeter.Memishian@Sun.COM } 25540Sstevel@tonic-gate out: 25550Sstevel@tonic-gate ipmp_snap_free(snap); 25560Sstevel@tonic-gate return (retval); 25570Sstevel@tonic-gate 25580Sstevel@tonic-gate default: 25590Sstevel@tonic-gate break; 25600Sstevel@tonic-gate 25610Sstevel@tonic-gate } 25620Sstevel@tonic-gate return (send_result(fd, IPMP_EPROTO, 0)); 25630Sstevel@tonic-gate } 25640Sstevel@tonic-gate 25650Sstevel@tonic-gate /* 25660Sstevel@tonic-gate * Send the group information pointed to by `grinfop' on file descriptor `fd'. 25670Sstevel@tonic-gate * Returns an IPMP error code. 25680Sstevel@tonic-gate */ 25690Sstevel@tonic-gate static unsigned int 25700Sstevel@tonic-gate send_groupinfo(int fd, ipmp_groupinfo_t *grinfop) 25710Sstevel@tonic-gate { 25720Sstevel@tonic-gate ipmp_iflist_t *iflistp = grinfop->gr_iflistp; 25738485SPeter.Memishian@Sun.COM ipmp_addrlist_t *adlistp = grinfop->gr_adlistp; 25740Sstevel@tonic-gate unsigned int retval; 25750Sstevel@tonic-gate 25760Sstevel@tonic-gate retval = ipmp_writetlv(fd, IPMP_GROUPINFO, sizeof (*grinfop), grinfop); 25770Sstevel@tonic-gate if (retval != IPMP_SUCCESS) 25780Sstevel@tonic-gate return (retval); 25790Sstevel@tonic-gate 25808485SPeter.Memishian@Sun.COM retval = ipmp_writetlv(fd, IPMP_IFLIST, 25818485SPeter.Memishian@Sun.COM IPMP_IFLIST_SIZE(iflistp->il_nif), iflistp); 25828485SPeter.Memishian@Sun.COM if (retval != IPMP_SUCCESS) 25838485SPeter.Memishian@Sun.COM return (retval); 25848485SPeter.Memishian@Sun.COM 25858485SPeter.Memishian@Sun.COM return (ipmp_writetlv(fd, IPMP_ADDRLIST, 25868485SPeter.Memishian@Sun.COM IPMP_ADDRLIST_SIZE(adlistp->al_naddr), adlistp)); 25870Sstevel@tonic-gate } 25880Sstevel@tonic-gate 25890Sstevel@tonic-gate /* 25900Sstevel@tonic-gate * Send the interface information pointed to by `ifinfop' on file descriptor 25910Sstevel@tonic-gate * `fd'. Returns an IPMP error code. 25920Sstevel@tonic-gate */ 25930Sstevel@tonic-gate static unsigned int 25940Sstevel@tonic-gate send_ifinfo(int fd, ipmp_ifinfo_t *ifinfop) 25950Sstevel@tonic-gate { 25968485SPeter.Memishian@Sun.COM ipmp_addrlist_t *adlist4p = ifinfop->if_targinfo4.it_targlistp; 25978485SPeter.Memishian@Sun.COM ipmp_addrlist_t *adlist6p = ifinfop->if_targinfo6.it_targlistp; 25988485SPeter.Memishian@Sun.COM unsigned int retval; 25998485SPeter.Memishian@Sun.COM 26008485SPeter.Memishian@Sun.COM retval = ipmp_writetlv(fd, IPMP_IFINFO, sizeof (*ifinfop), ifinfop); 26018485SPeter.Memishian@Sun.COM if (retval != IPMP_SUCCESS) 26028485SPeter.Memishian@Sun.COM return (retval); 26038485SPeter.Memishian@Sun.COM 26048485SPeter.Memishian@Sun.COM retval = ipmp_writetlv(fd, IPMP_ADDRLIST, 26058485SPeter.Memishian@Sun.COM IPMP_ADDRLIST_SIZE(adlist4p->al_naddr), adlist4p); 26068485SPeter.Memishian@Sun.COM if (retval != IPMP_SUCCESS) 26078485SPeter.Memishian@Sun.COM return (retval); 26088485SPeter.Memishian@Sun.COM 26098485SPeter.Memishian@Sun.COM return (ipmp_writetlv(fd, IPMP_ADDRLIST, 26108485SPeter.Memishian@Sun.COM IPMP_ADDRLIST_SIZE(adlist6p->al_naddr), adlist6p)); 26118485SPeter.Memishian@Sun.COM } 26128485SPeter.Memishian@Sun.COM 26138485SPeter.Memishian@Sun.COM /* 26148485SPeter.Memishian@Sun.COM * Send the address information pointed to by `adinfop' on file descriptor 26158485SPeter.Memishian@Sun.COM * `fd'. Returns an IPMP error code. 26168485SPeter.Memishian@Sun.COM */ 26178485SPeter.Memishian@Sun.COM static unsigned int 26188485SPeter.Memishian@Sun.COM send_addrinfo(int fd, ipmp_addrinfo_t *adinfop) 26198485SPeter.Memishian@Sun.COM { 26208485SPeter.Memishian@Sun.COM return (ipmp_writetlv(fd, IPMP_ADDRINFO, sizeof (*adinfop), adinfop)); 26210Sstevel@tonic-gate } 26220Sstevel@tonic-gate 26230Sstevel@tonic-gate /* 26240Sstevel@tonic-gate * Send the group list pointed to by `grlistp' on file descriptor `fd'. 26250Sstevel@tonic-gate * Returns an IPMP error code. 26260Sstevel@tonic-gate */ 26270Sstevel@tonic-gate static unsigned int 26280Sstevel@tonic-gate send_grouplist(int fd, ipmp_grouplist_t *grlistp) 26290Sstevel@tonic-gate { 26300Sstevel@tonic-gate return (ipmp_writetlv(fd, IPMP_GROUPLIST, 26310Sstevel@tonic-gate IPMP_GROUPLIST_SIZE(grlistp->gl_ngroup), grlistp)); 26320Sstevel@tonic-gate } 26330Sstevel@tonic-gate 26340Sstevel@tonic-gate /* 26350Sstevel@tonic-gate * Initialize an mi_result_t structure using `error' and `syserror' and 26360Sstevel@tonic-gate * send it on file descriptor `fd'. Returns an IPMP error code. 26370Sstevel@tonic-gate */ 26380Sstevel@tonic-gate static unsigned int 26390Sstevel@tonic-gate send_result(int fd, unsigned int error, int syserror) 26400Sstevel@tonic-gate { 26410Sstevel@tonic-gate mi_result_t me; 26420Sstevel@tonic-gate 26430Sstevel@tonic-gate me.me_mpathd_error = error; 26440Sstevel@tonic-gate if (error == IPMP_FAILURE) 26450Sstevel@tonic-gate me.me_sys_error = syserror; 26460Sstevel@tonic-gate else 26470Sstevel@tonic-gate me.me_sys_error = 0; 26480Sstevel@tonic-gate 26490Sstevel@tonic-gate return (ipmp_write(fd, &me, sizeof (me))); 26500Sstevel@tonic-gate } 26510Sstevel@tonic-gate 26520Sstevel@tonic-gate /* 26530Sstevel@tonic-gate * Daemonize the process. 26540Sstevel@tonic-gate */ 26550Sstevel@tonic-gate static boolean_t 26560Sstevel@tonic-gate daemonize(void) 26570Sstevel@tonic-gate { 26580Sstevel@tonic-gate switch (fork()) { 26590Sstevel@tonic-gate case -1: 26600Sstevel@tonic-gate return (_B_FALSE); 26610Sstevel@tonic-gate 26620Sstevel@tonic-gate case 0: 26630Sstevel@tonic-gate /* 26640Sstevel@tonic-gate * Lose our controlling terminal, and become both a session 26650Sstevel@tonic-gate * leader and a process group leader. 26660Sstevel@tonic-gate */ 26670Sstevel@tonic-gate if (setsid() == -1) 26680Sstevel@tonic-gate return (_B_FALSE); 26690Sstevel@tonic-gate 26700Sstevel@tonic-gate /* 26710Sstevel@tonic-gate * Under POSIX, a session leader can accidentally (through 26720Sstevel@tonic-gate * open(2)) acquire a controlling terminal if it does not 26730Sstevel@tonic-gate * have one. Just to be safe, fork() again so we are not a 26740Sstevel@tonic-gate * session leader. 26750Sstevel@tonic-gate */ 26760Sstevel@tonic-gate switch (fork()) { 26770Sstevel@tonic-gate case -1: 26780Sstevel@tonic-gate return (_B_FALSE); 26790Sstevel@tonic-gate 26800Sstevel@tonic-gate case 0: 26810Sstevel@tonic-gate (void) chdir("/"); 26820Sstevel@tonic-gate (void) umask(022); 26830Sstevel@tonic-gate (void) fdwalk(closefunc, NULL); 26840Sstevel@tonic-gate break; 26850Sstevel@tonic-gate 26860Sstevel@tonic-gate default: 26870Sstevel@tonic-gate _exit(EXIT_SUCCESS); 26880Sstevel@tonic-gate } 26890Sstevel@tonic-gate break; 26900Sstevel@tonic-gate 26910Sstevel@tonic-gate default: 26920Sstevel@tonic-gate _exit(EXIT_SUCCESS); 26930Sstevel@tonic-gate } 26940Sstevel@tonic-gate 26950Sstevel@tonic-gate return (_B_TRUE); 26960Sstevel@tonic-gate } 26970Sstevel@tonic-gate 26980Sstevel@tonic-gate /* 26990Sstevel@tonic-gate * The parent has created some fds before forking on purpose, keep them open. 27000Sstevel@tonic-gate */ 27010Sstevel@tonic-gate static int 27020Sstevel@tonic-gate closefunc(void *not_used, int fd) 27030Sstevel@tonic-gate /* ARGSUSED */ 27040Sstevel@tonic-gate { 27050Sstevel@tonic-gate if (fd != lsock_v4 && fd != lsock_v6) 27060Sstevel@tonic-gate (void) close(fd); 27070Sstevel@tonic-gate return (0); 27080Sstevel@tonic-gate } 27090Sstevel@tonic-gate 27100Sstevel@tonic-gate /* LOGGER */ 27110Sstevel@tonic-gate 27120Sstevel@tonic-gate #include <syslog.h> 27130Sstevel@tonic-gate 27140Sstevel@tonic-gate /* 27150Sstevel@tonic-gate * Logging routines. All routines log to syslog, unless the daemon is 27160Sstevel@tonic-gate * running in the foreground, in which case the logging goes to stderr. 27170Sstevel@tonic-gate * 27180Sstevel@tonic-gate * The following routines are available: 27190Sstevel@tonic-gate * 27200Sstevel@tonic-gate * logdebug(): A printf-like function for outputting debug messages 27210Sstevel@tonic-gate * (messages at LOG_DEBUG) that are only of use to developers. 27220Sstevel@tonic-gate * 27230Sstevel@tonic-gate * logtrace(): A printf-like function for outputting tracing messages 27240Sstevel@tonic-gate * (messages at LOG_INFO) from the daemon. This is typically used 27250Sstevel@tonic-gate * to log the receipt of interesting network-related conditions. 27260Sstevel@tonic-gate * 27270Sstevel@tonic-gate * logerr(): A printf-like function for outputting error messages 27280Sstevel@tonic-gate * (messages at LOG_ERR) from the daemon. 27290Sstevel@tonic-gate * 27300Sstevel@tonic-gate * logperror*(): A set of functions used to output error messages 27310Sstevel@tonic-gate * (messages at LOG_ERR); these automatically append strerror(errno) 27320Sstevel@tonic-gate * and a newline to the message passed to them. 27330Sstevel@tonic-gate * 27340Sstevel@tonic-gate * NOTE: since the logging functions write to syslog, the messages passed 27350Sstevel@tonic-gate * to them are not eligible for localization. Thus, gettext() must 27360Sstevel@tonic-gate * *not* be used. 27370Sstevel@tonic-gate */ 27380Sstevel@tonic-gate 27390Sstevel@tonic-gate static int logging = 0; 27400Sstevel@tonic-gate 27410Sstevel@tonic-gate static void 27420Sstevel@tonic-gate initlog(void) 27430Sstevel@tonic-gate { 27440Sstevel@tonic-gate logging++; 27456578Smeem openlog("in.mpathd", LOG_PID, LOG_DAEMON); 27460Sstevel@tonic-gate } 27470Sstevel@tonic-gate 27486578Smeem /* PRINTFLIKE2 */ 27490Sstevel@tonic-gate void 27506578Smeem logmsg(int pri, const char *fmt, ...) 27510Sstevel@tonic-gate { 27520Sstevel@tonic-gate va_list ap; 27530Sstevel@tonic-gate 27540Sstevel@tonic-gate va_start(ap, fmt); 27550Sstevel@tonic-gate 27560Sstevel@tonic-gate if (logging) 27576578Smeem vsyslog(pri, fmt, ap); 27580Sstevel@tonic-gate else 27590Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 27600Sstevel@tonic-gate va_end(ap); 27610Sstevel@tonic-gate } 27620Sstevel@tonic-gate 27630Sstevel@tonic-gate /* PRINTFLIKE1 */ 27640Sstevel@tonic-gate void 27656578Smeem logperror(const char *str) 27660Sstevel@tonic-gate { 27670Sstevel@tonic-gate if (logging) 27680Sstevel@tonic-gate syslog(LOG_ERR, "%s: %m\n", str); 27690Sstevel@tonic-gate else 27700Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); 27710Sstevel@tonic-gate } 27720Sstevel@tonic-gate 27730Sstevel@tonic-gate void 27746578Smeem logperror_pii(struct phyint_instance *pii, const char *str) 27750Sstevel@tonic-gate { 27760Sstevel@tonic-gate if (logging) { 27770Sstevel@tonic-gate syslog(LOG_ERR, "%s (%s %s): %m\n", 27780Sstevel@tonic-gate str, AF_STR(pii->pii_af), pii->pii_phyint->pi_name); 27790Sstevel@tonic-gate } else { 27800Sstevel@tonic-gate (void) fprintf(stderr, "%s (%s %s): %s\n", 27810Sstevel@tonic-gate str, AF_STR(pii->pii_af), pii->pii_phyint->pi_name, 27820Sstevel@tonic-gate strerror(errno)); 27830Sstevel@tonic-gate } 27840Sstevel@tonic-gate } 27850Sstevel@tonic-gate 27860Sstevel@tonic-gate void 27876578Smeem logperror_li(struct logint *li, const char *str) 27880Sstevel@tonic-gate { 27890Sstevel@tonic-gate struct phyint_instance *pii = li->li_phyint_inst; 27900Sstevel@tonic-gate 27910Sstevel@tonic-gate if (logging) { 27920Sstevel@tonic-gate syslog(LOG_ERR, "%s (%s %s): %m\n", 27930Sstevel@tonic-gate str, AF_STR(pii->pii_af), li->li_name); 27940Sstevel@tonic-gate } else { 27950Sstevel@tonic-gate (void) fprintf(stderr, "%s (%s %s): %s\n", 27960Sstevel@tonic-gate str, AF_STR(pii->pii_af), li->li_name, 27970Sstevel@tonic-gate strerror(errno)); 27980Sstevel@tonic-gate } 27990Sstevel@tonic-gate } 28000Sstevel@tonic-gate 28010Sstevel@tonic-gate void 28020Sstevel@tonic-gate close_probe_socket(struct phyint_instance *pii, boolean_t polled) 28030Sstevel@tonic-gate { 28040Sstevel@tonic-gate if (polled) 28050Sstevel@tonic-gate (void) poll_remove(pii->pii_probe_sock); 28060Sstevel@tonic-gate (void) close(pii->pii_probe_sock); 28070Sstevel@tonic-gate pii->pii_probe_sock = -1; 28080Sstevel@tonic-gate pii->pii_basetime_inited = 0; 28090Sstevel@tonic-gate } 28108485SPeter.Memishian@Sun.COM 28118485SPeter.Memishian@Sun.COM boolean_t 28128485SPeter.Memishian@Sun.COM addrlist_add(addrlist_t **addrsp, const char *name, uint64_t flags, 28138485SPeter.Memishian@Sun.COM struct sockaddr_storage *ssp) 28148485SPeter.Memishian@Sun.COM { 28158485SPeter.Memishian@Sun.COM addrlist_t *addrp; 28168485SPeter.Memishian@Sun.COM 28178485SPeter.Memishian@Sun.COM if ((addrp = malloc(sizeof (addrlist_t))) == NULL) 28188485SPeter.Memishian@Sun.COM return (_B_FALSE); 28198485SPeter.Memishian@Sun.COM 28208485SPeter.Memishian@Sun.COM (void) strlcpy(addrp->al_name, name, LIFNAMSIZ); 28218485SPeter.Memishian@Sun.COM addrp->al_flags = flags; 28228485SPeter.Memishian@Sun.COM addrp->al_addr = *ssp; 28238485SPeter.Memishian@Sun.COM addrp->al_next = *addrsp; 28248485SPeter.Memishian@Sun.COM *addrsp = addrp; 28258485SPeter.Memishian@Sun.COM return (_B_TRUE); 28268485SPeter.Memishian@Sun.COM } 28278485SPeter.Memishian@Sun.COM 28288485SPeter.Memishian@Sun.COM void 28298485SPeter.Memishian@Sun.COM addrlist_free(addrlist_t **addrsp) 28308485SPeter.Memishian@Sun.COM { 28318485SPeter.Memishian@Sun.COM addrlist_t *addrp, *next_addrp; 28328485SPeter.Memishian@Sun.COM 28338485SPeter.Memishian@Sun.COM for (addrp = *addrsp; addrp != NULL; addrp = next_addrp) { 28348485SPeter.Memishian@Sun.COM next_addrp = addrp->al_next; 28358485SPeter.Memishian@Sun.COM free(addrp); 28368485SPeter.Memishian@Sun.COM } 28378485SPeter.Memishian@Sun.COM *addrsp = NULL; 28388485SPeter.Memishian@Sun.COM } 28398865SJonathan.Anderson@Sun.COM 28408865SJonathan.Anderson@Sun.COM /* 28418865SJonathan.Anderson@Sun.COM * Send down a T_OPTMGMT_REQ to ip asking for all data in the various 28428865SJonathan.Anderson@Sun.COM * tables defined by mib2.h. Pass the table information returned to the 28438865SJonathan.Anderson@Sun.COM * supplied function. 28448865SJonathan.Anderson@Sun.COM */ 28458865SJonathan.Anderson@Sun.COM static int 28468865SJonathan.Anderson@Sun.COM mibwalk(void (*proc)(mib_item_t *)) 28478865SJonathan.Anderson@Sun.COM { 28488865SJonathan.Anderson@Sun.COM mib_item_t *head_item = NULL; 28498865SJonathan.Anderson@Sun.COM mib_item_t *last_item = NULL; 28508865SJonathan.Anderson@Sun.COM mib_item_t *tmp; 28518865SJonathan.Anderson@Sun.COM struct strbuf ctlbuf, databuf; 28528865SJonathan.Anderson@Sun.COM int flags; 28538865SJonathan.Anderson@Sun.COM int rval; 28548865SJonathan.Anderson@Sun.COM uintptr_t buf[512 / sizeof (uintptr_t)]; 28558865SJonathan.Anderson@Sun.COM struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; 28568865SJonathan.Anderson@Sun.COM struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; 28578865SJonathan.Anderson@Sun.COM struct T_error_ack *tea = (struct T_error_ack *)buf; 28588865SJonathan.Anderson@Sun.COM struct opthdr *req, *optp; 28598865SJonathan.Anderson@Sun.COM int status = -1; 28608865SJonathan.Anderson@Sun.COM 28618865SJonathan.Anderson@Sun.COM if (mibfd == -1) { 28628865SJonathan.Anderson@Sun.COM if ((mibfd = open("/dev/ip", O_RDWR)) < 0) { 28638865SJonathan.Anderson@Sun.COM logperror("mibwalk(): ip open"); 28648865SJonathan.Anderson@Sun.COM return (status); 28658865SJonathan.Anderson@Sun.COM } 28668865SJonathan.Anderson@Sun.COM } 28678865SJonathan.Anderson@Sun.COM 28688865SJonathan.Anderson@Sun.COM tor->PRIM_type = T_SVR4_OPTMGMT_REQ; 28698865SJonathan.Anderson@Sun.COM tor->OPT_offset = sizeof (struct T_optmgmt_req); 28708865SJonathan.Anderson@Sun.COM tor->OPT_length = sizeof (struct opthdr); 28718865SJonathan.Anderson@Sun.COM tor->MGMT_flags = T_CURRENT; 28728865SJonathan.Anderson@Sun.COM 28738865SJonathan.Anderson@Sun.COM /* 28748865SJonathan.Anderson@Sun.COM * Note: we use the special level value below so that IP will return 28758865SJonathan.Anderson@Sun.COM * us information concerning IRE_MARK_TESTHIDDEN routes. 28768865SJonathan.Anderson@Sun.COM */ 28778865SJonathan.Anderson@Sun.COM req = (struct opthdr *)&tor[1]; 28788865SJonathan.Anderson@Sun.COM req->level = EXPER_IP_AND_TESTHIDDEN; 28798865SJonathan.Anderson@Sun.COM req->name = 0; 28808865SJonathan.Anderson@Sun.COM req->len = 0; 28818865SJonathan.Anderson@Sun.COM 28828865SJonathan.Anderson@Sun.COM ctlbuf.buf = (char *)&buf; 28838865SJonathan.Anderson@Sun.COM ctlbuf.len = tor->OPT_length + tor->OPT_offset; 28848865SJonathan.Anderson@Sun.COM 28858865SJonathan.Anderson@Sun.COM if (putmsg(mibfd, &ctlbuf, NULL, 0) == -1) { 28868865SJonathan.Anderson@Sun.COM logperror("mibwalk(): putmsg(ctl)"); 28878865SJonathan.Anderson@Sun.COM return (status); 28888865SJonathan.Anderson@Sun.COM } 28898865SJonathan.Anderson@Sun.COM 28908865SJonathan.Anderson@Sun.COM /* 28918865SJonathan.Anderson@Sun.COM * The response consists of multiple T_OPTMGMT_ACK msgs, 1 msg for 28928865SJonathan.Anderson@Sun.COM * each table defined in mib2.h. Each T_OPTMGMT_ACK msg contains 28938865SJonathan.Anderson@Sun.COM * a control and data part. The control part contains a struct 28948865SJonathan.Anderson@Sun.COM * T_optmgmt_ack followed by a struct opthdr. The 'opthdr' identifies 28958865SJonathan.Anderson@Sun.COM * the level, name and length of the data in the data part. The 28968865SJonathan.Anderson@Sun.COM * data part contains the actual table data. The last message 28978865SJonathan.Anderson@Sun.COM * is an end-of-data (EOD), consisting of a T_OPTMGMT_ACK and a 28988865SJonathan.Anderson@Sun.COM * single option with zero optlen. 28998865SJonathan.Anderson@Sun.COM */ 29008865SJonathan.Anderson@Sun.COM for (;;) { 29018865SJonathan.Anderson@Sun.COM errno = flags = 0; 29028865SJonathan.Anderson@Sun.COM ctlbuf.maxlen = sizeof (buf); 29038865SJonathan.Anderson@Sun.COM rval = getmsg(mibfd, &ctlbuf, NULL, &flags); 29048865SJonathan.Anderson@Sun.COM if (rval & MORECTL || rval < 0) { 29058865SJonathan.Anderson@Sun.COM if (errno == EINTR) 29068865SJonathan.Anderson@Sun.COM continue; 29078865SJonathan.Anderson@Sun.COM logerr("mibwalk(): getmsg(ctl) ret: %d err: %d\n", 29088865SJonathan.Anderson@Sun.COM rval, errno); 29098865SJonathan.Anderson@Sun.COM goto error; 29108865SJonathan.Anderson@Sun.COM } 29118865SJonathan.Anderson@Sun.COM if (ctlbuf.len < sizeof (t_scalar_t)) { 29128865SJonathan.Anderson@Sun.COM logerr("mibwalk(): ctlbuf.len %d\n", ctlbuf.len); 29138865SJonathan.Anderson@Sun.COM goto error; 29148865SJonathan.Anderson@Sun.COM } 29158865SJonathan.Anderson@Sun.COM 29168865SJonathan.Anderson@Sun.COM switch (toa->PRIM_type) { 29178865SJonathan.Anderson@Sun.COM case T_ERROR_ACK: 29188865SJonathan.Anderson@Sun.COM if (ctlbuf.len < sizeof (struct T_error_ack)) { 29198865SJonathan.Anderson@Sun.COM logerr("mibwalk(): T_ERROR_ACK ctlbuf " 29208865SJonathan.Anderson@Sun.COM "too short: %d\n", ctlbuf.len); 29218865SJonathan.Anderson@Sun.COM goto error; 29228865SJonathan.Anderson@Sun.COM } 29238865SJonathan.Anderson@Sun.COM logerr("mibwalk(): T_ERROR_ACK: TLI_err = 0x%lx: %s\n" 29248865SJonathan.Anderson@Sun.COM " UNIX_err = 0x%lx\n", tea->TLI_error, 29258865SJonathan.Anderson@Sun.COM t_strerror(tea->TLI_error), tea->UNIX_error); 29268865SJonathan.Anderson@Sun.COM goto error; 29278865SJonathan.Anderson@Sun.COM 29288865SJonathan.Anderson@Sun.COM case T_OPTMGMT_ACK: 29298865SJonathan.Anderson@Sun.COM optp = (struct opthdr *)&toa[1]; 29308865SJonathan.Anderson@Sun.COM if (ctlbuf.len < (sizeof (struct T_optmgmt_ack) + 29318865SJonathan.Anderson@Sun.COM sizeof (struct opthdr))) { 29328865SJonathan.Anderson@Sun.COM logerr("mibwalk(): T_OPTMGMT_ACK ctlbuf too " 29338865SJonathan.Anderson@Sun.COM "short: %d\n", ctlbuf.len); 29348865SJonathan.Anderson@Sun.COM goto error; 29358865SJonathan.Anderson@Sun.COM } 29368865SJonathan.Anderson@Sun.COM if (toa->MGMT_flags != T_SUCCESS) { 29378865SJonathan.Anderson@Sun.COM logerr("mibwalk(): MGMT_flags != T_SUCCESS: " 29388865SJonathan.Anderson@Sun.COM "0x%lx\n", toa->MGMT_flags); 29398865SJonathan.Anderson@Sun.COM goto error; 29408865SJonathan.Anderson@Sun.COM } 29418865SJonathan.Anderson@Sun.COM break; 29428865SJonathan.Anderson@Sun.COM 29438865SJonathan.Anderson@Sun.COM default: 29448865SJonathan.Anderson@Sun.COM goto error; 29458865SJonathan.Anderson@Sun.COM } 29468865SJonathan.Anderson@Sun.COM /* The following assert also implies MGMT_flags == T_SUCCESS */ 29478865SJonathan.Anderson@Sun.COM assert(toa->PRIM_type == T_OPTMGMT_ACK); 29488865SJonathan.Anderson@Sun.COM 29498865SJonathan.Anderson@Sun.COM /* 29508865SJonathan.Anderson@Sun.COM * We have reached the end of this T_OPTMGMT_ACK 29518865SJonathan.Anderson@Sun.COM * message. If this is the last message i.e EOD, 29528865SJonathan.Anderson@Sun.COM * break, else process the next T_OPTMGMT_ACK msg. 29538865SJonathan.Anderson@Sun.COM */ 29548865SJonathan.Anderson@Sun.COM if (rval == 0) { 29558865SJonathan.Anderson@Sun.COM if (optp->len == 0 && optp->name == 0 && 29568865SJonathan.Anderson@Sun.COM optp->level == 0) { 29578865SJonathan.Anderson@Sun.COM /* This is the EOD message. */ 29588865SJonathan.Anderson@Sun.COM break; 29598865SJonathan.Anderson@Sun.COM } 29608865SJonathan.Anderson@Sun.COM /* Not EOD but no data to retrieve */ 29618865SJonathan.Anderson@Sun.COM continue; 29628865SJonathan.Anderson@Sun.COM } 29638865SJonathan.Anderson@Sun.COM 29648865SJonathan.Anderson@Sun.COM /* 29658865SJonathan.Anderson@Sun.COM * We should only be here if MOREDATA was set. 29668865SJonathan.Anderson@Sun.COM * Allocate an empty mib_item_t and link into the list 29678865SJonathan.Anderson@Sun.COM * of MIB items. 29688865SJonathan.Anderson@Sun.COM */ 29698865SJonathan.Anderson@Sun.COM if ((tmp = malloc(sizeof (*tmp))) == NULL) { 29708865SJonathan.Anderson@Sun.COM logperror("mibwalk(): malloc() failed."); 29718865SJonathan.Anderson@Sun.COM goto error; 29728865SJonathan.Anderson@Sun.COM } 29738865SJonathan.Anderson@Sun.COM if (last_item != NULL) 29748865SJonathan.Anderson@Sun.COM last_item->mi_next = tmp; 29758865SJonathan.Anderson@Sun.COM else 29768865SJonathan.Anderson@Sun.COM head_item = tmp; 29778865SJonathan.Anderson@Sun.COM last_item = tmp; 29788865SJonathan.Anderson@Sun.COM last_item->mi_next = NULL; 29798865SJonathan.Anderson@Sun.COM last_item->mi_opthdr = *optp; 29808865SJonathan.Anderson@Sun.COM last_item->mi_valp = malloc(optp->len); 29818865SJonathan.Anderson@Sun.COM if (last_item->mi_valp == NULL) { 29828865SJonathan.Anderson@Sun.COM logperror("mibwalk(): malloc() failed."); 29838865SJonathan.Anderson@Sun.COM goto error; 29848865SJonathan.Anderson@Sun.COM } 29858865SJonathan.Anderson@Sun.COM 29868865SJonathan.Anderson@Sun.COM databuf.maxlen = last_item->mi_opthdr.len; 29878865SJonathan.Anderson@Sun.COM databuf.buf = (char *)last_item->mi_valp; 29888865SJonathan.Anderson@Sun.COM databuf.len = 0; 29898865SJonathan.Anderson@Sun.COM 29908865SJonathan.Anderson@Sun.COM /* Retrieve the actual MIB data */ 29918865SJonathan.Anderson@Sun.COM for (;;) { 29928865SJonathan.Anderson@Sun.COM flags = 0; 29938865SJonathan.Anderson@Sun.COM if ((rval = getmsg(mibfd, NULL, &databuf, 29948865SJonathan.Anderson@Sun.COM &flags)) != 0) { 29958865SJonathan.Anderson@Sun.COM if (rval < 0 && errno == EINTR) 29968865SJonathan.Anderson@Sun.COM continue; 29978865SJonathan.Anderson@Sun.COM /* 29988865SJonathan.Anderson@Sun.COM * We shouldn't get MOREDATA here so treat that 29998865SJonathan.Anderson@Sun.COM * as an error. 30008865SJonathan.Anderson@Sun.COM */ 30018865SJonathan.Anderson@Sun.COM logperror("mibwalk(): getmsg(data)"); 30028865SJonathan.Anderson@Sun.COM goto error; 30038865SJonathan.Anderson@Sun.COM } 30048865SJonathan.Anderson@Sun.COM break; 30058865SJonathan.Anderson@Sun.COM } 30068865SJonathan.Anderson@Sun.COM } 30078865SJonathan.Anderson@Sun.COM status = 0; 30088865SJonathan.Anderson@Sun.COM /* Pass the accumulated MIB data to the supplied function pointer */ 30098865SJonathan.Anderson@Sun.COM (*proc)(head_item); 30108865SJonathan.Anderson@Sun.COM error: 30118865SJonathan.Anderson@Sun.COM while (head_item != NULL) { 30128865SJonathan.Anderson@Sun.COM tmp = head_item; 30138865SJonathan.Anderson@Sun.COM head_item = tmp->mi_next; 30148865SJonathan.Anderson@Sun.COM free(tmp->mi_valp); 30158865SJonathan.Anderson@Sun.COM free(tmp); 30168865SJonathan.Anderson@Sun.COM } 30178865SJonathan.Anderson@Sun.COM return (status); 30188865SJonathan.Anderson@Sun.COM } 30198865SJonathan.Anderson@Sun.COM 30208865SJonathan.Anderson@Sun.COM /* 30218865SJonathan.Anderson@Sun.COM * Parse the supplied mib2 information to get the size of routing table 30228865SJonathan.Anderson@Sun.COM * entries. This is needed when running in a branded zone where the 30238865SJonathan.Anderson@Sun.COM * Solaris application environment and the Solaris kernel may not be the 30248865SJonathan.Anderson@Sun.COM * the same release version. 30258865SJonathan.Anderson@Sun.COM */ 30268865SJonathan.Anderson@Sun.COM static void 30278865SJonathan.Anderson@Sun.COM mib_get_constants(mib_item_t *item) 30288865SJonathan.Anderson@Sun.COM { 30298865SJonathan.Anderson@Sun.COM mib2_ip_t *ipv4; 30308865SJonathan.Anderson@Sun.COM mib2_ipv6IfStatsEntry_t *ipv6; 30318865SJonathan.Anderson@Sun.COM 30328865SJonathan.Anderson@Sun.COM for (; item != NULL; item = item->mi_next) { 30338865SJonathan.Anderson@Sun.COM if (item->mi_opthdr.name != 0) 30348865SJonathan.Anderson@Sun.COM continue; 30358865SJonathan.Anderson@Sun.COM if (item->mi_opthdr.level == MIB2_IP) { 30368865SJonathan.Anderson@Sun.COM ipv4 = (mib2_ip_t *)item->mi_valp; 30378865SJonathan.Anderson@Sun.COM ipRouteEntrySize = ipv4->ipRouteEntrySize; 30388865SJonathan.Anderson@Sun.COM } else if (item->mi_opthdr.level == MIB2_IP6) { 30398865SJonathan.Anderson@Sun.COM ipv6 = (mib2_ipv6IfStatsEntry_t *)item->mi_valp; 30408865SJonathan.Anderson@Sun.COM ipv6RouteEntrySize = ipv6->ipv6RouteEntrySize; 30418865SJonathan.Anderson@Sun.COM } 30428865SJonathan.Anderson@Sun.COM } 30438865SJonathan.Anderson@Sun.COM } 3044