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