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