17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5921e7e07Smeem  * Common Development and Distribution License (the "License").
6921e7e07Smeem  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22e11c3f44Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2480d556f9SHans Rosenfeld  *
2580d556f9SHans Rosenfeld  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
267c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate #include "mpd_defs.h"
297c478bd9Sstevel@tonic-gate #include "mpd_tables.h"
317c478bd9Sstevel@tonic-gate int debug = 0;				/* Debug flag */
327c478bd9Sstevel@tonic-gate static int pollfd_num = 0;		/* Num. of poll descriptors */
337c478bd9Sstevel@tonic-gate static struct pollfd *pollfds = NULL;	/* Array of poll descriptors */
347c478bd9Sstevel@tonic-gate 					/* All times below in ms */
357c478bd9Sstevel@tonic-gate int	user_failure_detection_time;	/* user specified failure detection */
367c478bd9Sstevel@tonic-gate 					/* time (fdt) */
377c478bd9Sstevel@tonic-gate int	user_probe_interval;		/* derived from user specified fdt */
3927438c18SJon Anderson /*
4027438c18SJon Anderson  * Structure to store mib2 information returned by the kernel.
4127438c18SJon Anderson  * This is used to process routing table information.
4227438c18SJon Anderson  */
4327438c18SJon Anderson typedef struct mib_item_s {
4427438c18SJon Anderson 	struct mib_item_s	*mi_next;
4527438c18SJon Anderson 	struct opthdr		mi_opthdr;
4627438c18SJon Anderson 	void			*mi_valp;
4727438c18SJon Anderson } mib_item_t;
4827438c18SJon Anderson 
497c478bd9Sstevel@tonic-gate static int	rtsock_v4;		/* AF_INET routing socket */
507c478bd9Sstevel@tonic-gate static int	rtsock_v6;		/* AF_INET6 routing socket */
517c478bd9Sstevel@tonic-gate int	ifsock_v4 = -1;			/* IPv4 socket for ioctls  */
527c478bd9Sstevel@tonic-gate int	ifsock_v6 = -1;			/* IPv6 socket for ioctls  */
537c478bd9Sstevel@tonic-gate static int	lsock_v4;		/* Listen socket to detect mpathd */
547c478bd9Sstevel@tonic-gate static int	lsock_v6;		/* Listen socket to detect mpathd */
557c478bd9Sstevel@tonic-gate static int	mibfd = -1;		/* fd to get mib info */
567c478bd9Sstevel@tonic-gate static boolean_t force_mcast = _B_FALSE; /* Only for test purposes */
587c478bd9Sstevel@tonic-gate static uint_t	last_initifs_time;	/* Time when initifs was last run */
597c478bd9Sstevel@tonic-gate static	char **argv0;			/* Saved for re-exec on SIGHUP */
607c478bd9Sstevel@tonic-gate boolean_t handle_link_notifications = _B_TRUE;
6127438c18SJon Anderson static int	ipRouteEntrySize;	/* Size of IPv4 route entry */
6227438c18SJon Anderson static int	ipv6RouteEntrySize;	/* Size of IPv6 route entry */
647c478bd9Sstevel@tonic-gate static void	initlog(void);
657c478bd9Sstevel@tonic-gate static void	run_timeouts(void);
667c478bd9Sstevel@tonic-gate static void	initifs(void);
677c478bd9Sstevel@tonic-gate static void	check_if_removed(struct phyint_instance *pii);
687c478bd9Sstevel@tonic-gate static void	select_test_ifs(void);
6927438c18SJon Anderson static void	update_router_list(mib_item_t *item);
7027438c18SJon Anderson static void	mib_get_constants(mib_item_t *item);
7127438c18SJon Anderson static int	mibwalk(void (*proc)(mib_item_t *));
727c478bd9Sstevel@tonic-gate static void	ire_process_v4(mib2_ipRouteEntry_t *buf, size_t len);
737c478bd9Sstevel@tonic-gate static void	ire_process_v6(mib2_ipv6RouteEntry_t *buf, size_t len);
747c478bd9Sstevel@tonic-gate static void	router_add_common(int af, char *ifname,
757c478bd9Sstevel@tonic-gate     struct in6_addr nexthop);
767c478bd9Sstevel@tonic-gate static void	init_router_targets();
777c478bd9Sstevel@tonic-gate static void	cleanup(void);
787c478bd9Sstevel@tonic-gate static int	setup_listener(int af);
797c478bd9Sstevel@tonic-gate static void	check_config(void);
80e6ed03fcSmeem static void	check_testconfig(void);
8106cdd167Smeem static void	check_addr_unique(struct phyint_instance *,
8206cdd167Smeem     struct sockaddr_storage *);
837c478bd9Sstevel@tonic-gate static void	init_host_targets(void);
847c478bd9Sstevel@tonic-gate static void	dup_host_targets(struct phyint_instance *desired_pii);
857c478bd9Sstevel@tonic-gate static void	loopback_cmd(int sock, int family);
867c478bd9Sstevel@tonic-gate static boolean_t daemonize(void);
877c478bd9Sstevel@tonic-gate static int	closefunc(void *, int);
887c478bd9Sstevel@tonic-gate static unsigned int process_cmd(int newfd, union mi_commands *mpi);
897c478bd9Sstevel@tonic-gate static unsigned int process_query(int fd, mi_query_t *miq);
90e11c3f44Smeem static unsigned int send_addrinfo(int fd, ipmp_addrinfo_t *adinfop);
917c478bd9Sstevel@tonic-gate static unsigned int send_groupinfo(int fd, ipmp_groupinfo_t *grinfop);
927c478bd9Sstevel@tonic-gate static unsigned int send_grouplist(int fd, ipmp_grouplist_t *grlistp);
937c478bd9Sstevel@tonic-gate static unsigned int send_ifinfo(int fd, ipmp_ifinfo_t *ifinfop);
947c478bd9Sstevel@tonic-gate static unsigned int send_result(int fd, unsigned int error, int syserror);
96e11c3f44Smeem addrlist_t *localaddrs;
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * Return the current time in milliseconds (from an arbitrary reference)
1007c478bd9Sstevel@tonic-gate  * truncated to fit into an int. Truncation is ok since we are interested
1017c478bd9Sstevel@tonic-gate  * only in differences and not the absolute values.
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate uint_t
getcurrenttime(void)1047c478bd9Sstevel@tonic-gate getcurrenttime(void)
1057c478bd9Sstevel@tonic-gate {
1067c478bd9Sstevel@tonic-gate 	uint_t	cur_time;	/* In ms */
1087c478bd9Sstevel@tonic-gate 	/*
1097c478bd9Sstevel@tonic-gate 	 * Use of a non-user-adjustable source of time is
1107c478bd9Sstevel@tonic-gate 	 * required. However millisecond precision is sufficient.
1117c478bd9Sstevel@tonic-gate 	 * divide by 10^6
1127c478bd9Sstevel@tonic-gate 	 */
1137c478bd9Sstevel@tonic-gate 	cur_time = (uint_t)(gethrtime() / 1000000LL);
1147c478bd9Sstevel@tonic-gate 	return (cur_time);
1157c478bd9Sstevel@tonic-gate }
117e6ed03fcSmeem uint64_t
getcurrentsec(void)118e6ed03fcSmeem getcurrentsec(void)
119e6ed03fcSmeem {
120e6ed03fcSmeem 	return (gethrtime() / NANOSEC);
121e6ed03fcSmeem }
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate  * Add fd to the set being polled. Returns 0 if ok; -1 if failed.
1257c478bd9Sstevel@tonic-gate  */
1267c478bd9Sstevel@tonic-gate int
poll_add(int fd)1277c478bd9Sstevel@tonic-gate poll_add(int fd)
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate 	int i;
1307c478bd9Sstevel@tonic-gate 	int new_num;
1317c478bd9Sstevel@tonic-gate 	struct pollfd *newfds;
1327c478bd9Sstevel@tonic-gate retry:
1337c478bd9Sstevel@tonic-gate 	/* Check if already present */
1347c478bd9Sstevel@tonic-gate 	for (i = 0; i < pollfd_num; i++) {
1357c478bd9Sstevel@tonic-gate 		if (pollfds[i].fd == fd)
1367c478bd9Sstevel@tonic-gate 			return (0);
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate 	/* Check for empty spot already present */
1397c478bd9Sstevel@tonic-gate 	for (i = 0; i < pollfd_num; i++) {
1407c478bd9Sstevel@tonic-gate 		if (pollfds[i].fd == -1) {
1417c478bd9Sstevel@tonic-gate 			pollfds[i].fd = fd;
1427c478bd9Sstevel@tonic-gate 			return (0);
1437c478bd9Sstevel@tonic-gate 		}
1447c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 	/* Allocate space for 32 more fds and initialize to -1 */
1477c478bd9Sstevel@tonic-gate 	new_num = pollfd_num + 32;
1487c478bd9Sstevel@tonic-gate 	newfds = realloc(pollfds, new_num * sizeof (struct pollfd));
1497c478bd9Sstevel@tonic-gate 	if (newfds == NULL) {
1507c478bd9Sstevel@tonic-gate 		logperror("poll_add: realloc");
1517c478bd9Sstevel@tonic-gate 		return (-1);
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate 	for (i = pollfd_num; i < new_num; i++) {
1547c478bd9Sstevel@tonic-gate 		newfds[i].fd = -1;
1557c478bd9Sstevel@tonic-gate 		newfds[i].events = POLLIN;
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate 	pollfd_num = new_num;
1587c478bd9Sstevel@tonic-gate 	pollfds = newfds;
1597c478bd9Sstevel@tonic-gate 	goto retry;
1607c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate /*
1637c478bd9Sstevel@tonic-gate  * Remove fd from the set being polled. Returns 0 if ok; -1 if failed.
1647c478bd9Sstevel@tonic-gate  */
165e11c3f44Smeem int
poll_remove(int fd)1667c478bd9Sstevel@tonic-gate poll_remove(int fd)
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate 	int i;
1707c478bd9Sstevel@tonic-gate 	/* Check if already present */
1717c478bd9Sstevel@tonic-gate 	for (i = 0; i < pollfd_num; i++) {
1727c478bd9Sstevel@tonic-gate 		if (pollfds[i].fd == fd) {
1737c478bd9Sstevel@tonic-gate 			pollfds[i].fd = -1;
1747c478bd9Sstevel@tonic-gate 			return (0);
1757c478bd9Sstevel@tonic-gate 		}
1767c478bd9Sstevel@tonic-gate 	}
1777c478bd9Sstevel@tonic-gate 	return (-1);
1787c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate  * Extract information about the phyint instance. If the phyint instance still
1827c478bd9Sstevel@tonic-gate  * exists in the kernel then set pii_in_use, else clear it. check_if_removed()
1837c478bd9Sstevel@tonic-gate  * will use it to detect phyint instances that don't exist any longer and
1847c478bd9Sstevel@tonic-gate  * remove them, from our database of phyint instances.
1857c478bd9Sstevel@tonic-gate  * Return value:
1867c478bd9Sstevel@tonic-gate  *	returns true if the phyint instance exists in the kernel,
1877c478bd9Sstevel@tonic-gate  *	returns false otherwise
1887c478bd9Sstevel@tonic-gate  */
1897c478bd9Sstevel@tonic-gate static boolean_t
pii_process(int af,char * name,struct phyint_instance ** pii_p)1907c478bd9Sstevel@tonic-gate pii_process(int af, char *name, struct phyint_instance **pii_p)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	int err;
1937c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
1947c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii_other;
1967c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
1977c478bd9Sstevel@tonic-gate 		logdebug("pii_process(%s %s)\n", AF_STR(af), name);
1997c478bd9Sstevel@tonic-gate 	pii = phyint_inst_lookup(af, name);
2007c478bd9Sstevel@tonic-gate 	if (pii == NULL) {
2017c478bd9Sstevel@tonic-gate 		/*
2027c478bd9Sstevel@tonic-gate 		 * Phyint instance does not exist in our tables,
2037c478bd9Sstevel@tonic-gate 		 * create new phyint instance
2047c478bd9Sstevel@tonic-gate 		 */
2057c478bd9Sstevel@tonic-gate 		pii = phyint_inst_init_from_k(af, name);
2067c478bd9Sstevel@tonic-gate 	} else {
2077c478bd9Sstevel@tonic-gate 		/* Phyint exists in our tables */
2087c478bd9Sstevel@tonic-gate 		err = phyint_inst_update_from_k(pii);
2107c478bd9Sstevel@tonic-gate 		switch (err) {
2117c478bd9Sstevel@tonic-gate 		case PI_IOCTL_ERROR:
2127c478bd9Sstevel@tonic-gate 			/* Some ioctl error. don't change anything */
2137c478bd9Sstevel@tonic-gate 			pii->pii_in_use = 1;
2147c478bd9Sstevel@tonic-gate 			break;
2167c478bd9Sstevel@tonic-gate 		case PI_GROUP_CHANGED:
2177c478bd9Sstevel@tonic-gate 		case PI_IFINDEX_CHANGED:
2187c478bd9Sstevel@tonic-gate 			/*
219e11c3f44Smeem 			 * Interface index or group membership has changed.
220e11c3f44Smeem 			 * Delete the old state and recreate based on the new
221e11c3f44Smeem 			 * state (it may no longer be in a group).
2227c478bd9Sstevel@tonic-gate 			 */
2237c478bd9Sstevel@tonic-gate 			pii_other = phyint_inst_other(pii);
2247c478bd9Sstevel@tonic-gate 			if (pii_other != NULL)
2257c478bd9Sstevel@tonic-gate 				phyint_inst_delete(pii_other);
2267c478bd9Sstevel@tonic-gate 			phyint_inst_delete(pii);
2277c478bd9Sstevel@tonic-gate 			pii = phyint_inst_init_from_k(af, name);
2287c478bd9Sstevel@tonic-gate 			break;
2307c478bd9Sstevel@tonic-gate 		case PI_DELETED:
2317c478bd9Sstevel@tonic-gate 			/* Phyint instance has disappeared from kernel */
2327c478bd9Sstevel@tonic-gate 			pii->pii_in_use = 0;
2337c478bd9Sstevel@tonic-gate 			break;
2357c478bd9Sstevel@tonic-gate 		case PI_OK:
2367c478bd9Sstevel@tonic-gate 			/* Phyint instance exists and is fine */
2377c478bd9Sstevel@tonic-gate 			pii->pii_in_use = 1;
2387c478bd9Sstevel@tonic-gate 			break;
2407c478bd9Sstevel@tonic-gate 		default:
2417c478bd9Sstevel@tonic-gate 			/* Unknown status */
2427c478bd9Sstevel@tonic-gate 			logerr("pii_process: Unknown status %d\n", err);
2437c478bd9Sstevel@tonic-gate 			break;
2447c478bd9Sstevel@tonic-gate 		}
2457c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 	*pii_p = pii;
2487c478bd9Sstevel@tonic-gate 	if (pii != NULL)
2497c478bd9Sstevel@tonic-gate 		return (pii->pii_in_use ? _B_TRUE : _B_FALSE);
2507c478bd9Sstevel@tonic-gate 	else
2517c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
2527c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate  * Scan all interfaces to detect changes as well as new and deleted interfaces
2567c478bd9Sstevel@tonic-gate  */
2577c478bd9Sstevel@tonic-gate static void
initifs()2587c478bd9Sstevel@tonic-gate initifs()
2597c478bd9Sstevel@tonic-gate {
260e11c3f44Smeem 	int	i, nlifr;
2617c478bd9Sstevel@tonic-gate 	int	af;
2627c478bd9Sstevel@tonic-gate 	char	*cp;
2637c478bd9Sstevel@tonic-gate 	char	*buf;
264e11c3f44Smeem 	int	sockfd;
265e11c3f44Smeem 	uint64_t	flags;
2667c478bd9Sstevel@tonic-gate 	struct lifnum	lifn;
2677c478bd9Sstevel@tonic-gate 	struct lifconf	lifc;
268e11c3f44Smeem 	struct lifreq	lifreq;
2697c478bd9Sstevel@tonic-gate 	struct lifreq	*lifr;
2707c478bd9Sstevel@tonic-gate 	struct logint	*li;
2717c478bd9Sstevel@tonic-gate 	struct phyint_instance *pii;
2727c478bd9Sstevel@tonic-gate 	struct phyint_instance *next_pii;
273e11c3f44Smeem 	struct phyint_group *pg, *next_pg;
274e11c3f44Smeem 	char		pi_name[LIFNAMSIZ + 1];
2767c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
2777c478bd9Sstevel@tonic-gate 		logdebug("initifs: Scanning interfaces\n");
2797c478bd9Sstevel@tonic-gate 	last_initifs_time = getcurrenttime();
28187e66ffcSrk 	/*
282e11c3f44Smeem 	 * Free the existing local address list; we'll build a new list below.
28387e66ffcSrk 	 */
284e11c3f44Smeem 	addrlist_free(&localaddrs);
2867c478bd9Sstevel@tonic-gate 	/*
2877c478bd9Sstevel@tonic-gate 	 * Mark the interfaces so that we can find phyints and logints
2887c478bd9Sstevel@tonic-gate 	 * which have disappeared from the kernel. pii_process() and
2897c478bd9Sstevel@tonic-gate 	 * logint_init_from_k() will set {pii,li}_in_use when they find
2907c478bd9Sstevel@tonic-gate 	 * the interface in the kernel. Also, clear dupaddr bit on probe
2917c478bd9Sstevel@tonic-gate 	 * logint. check_addr_unique() will set the dupaddr bit on the
2927c478bd9Sstevel@tonic-gate 	 * probe logint, if the testaddress is not unique.
2937c478bd9Sstevel@tonic-gate 	 */
2947c478bd9Sstevel@tonic-gate 	for (pii = phyint_instances; pii != NULL; pii = pii->pii_next) {
2957c478bd9Sstevel@tonic-gate 		pii->pii_in_use = 0;
2967c478bd9Sstevel@tonic-gate 		for (li = pii->pii_logint; li != NULL; li = li->li_next) {
2977c478bd9Sstevel@tonic-gate 			li->li_in_use = 0;
2987c478bd9Sstevel@tonic-gate 			if (pii->pii_probe_logint == li)
2997c478bd9Sstevel@tonic-gate 				li->li_dupaddr = 0;
3007c478bd9Sstevel@tonic-gate 		}
3017c478bd9Sstevel@tonic-gate 	}
303e11c3f44Smeem 	/*
304e11c3f44Smeem 	 * As above, mark groups so that we can detect IPMP interfaces which
305e11c3f44Smeem 	 * have been removed from the kernel.  Also, delete the group address
306e11c3f44Smeem 	 * list since we'll iteratively recreate it below.
307e11c3f44Smeem 	 */
308e11c3f44Smeem 	for (pg = phyint_groups; pg != NULL; pg = pg->pg_next) {
309e11c3f44Smeem 		pg->pg_in_use = _B_FALSE;
310e11c3f44Smeem 		addrlist_free(&pg->pg_addrs);
311e11c3f44Smeem 	}
3137c478bd9Sstevel@tonic-gate 	lifn.lifn_family = AF_UNSPEC;
314e11c3f44Smeem 	lifn.lifn_flags = LIFC_ALLZONES | LIFC_UNDER_IPMP;
315e11c3f44Smeem again:
3167c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock_v4, SIOCGLIFNUM, (char *)&lifn) < 0) {
317e11c3f44Smeem 		logperror("initifs: ioctl (get interface count)");
3187c478bd9Sstevel@tonic-gate 		return;
3197c478bd9Sstevel@tonic-gate 	}
320e11c3f44Smeem 	/*
321e11c3f44Smeem 	 * Pad the interface count to detect when additional interfaces have
322e11c3f44Smeem 	 * been configured between SIOCGLIFNUM and SIOCGLIFCONF.
323e11c3f44Smeem 	 */
324e11c3f44Smeem 	lifn.lifn_count += 4;
326e11c3f44Smeem 	if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) {
3277c478bd9Sstevel@tonic-gate 		logperror("initifs: calloc");
3287c478bd9Sstevel@tonic-gate 		return;
3297c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 	lifc.lifc_family = AF_UNSPEC;
332e11c3f44Smeem 	lifc.lifc_flags = LIFC_ALLZONES | LIFC_UNDER_IPMP;
333e11c3f44Smeem 	lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq);
3347c478bd9Sstevel@tonic-gate 	lifc.lifc_buf = buf;
3367c478bd9Sstevel@tonic-gate 	if (ioctl(ifsock_v4, SIOCGLIFCONF, (char *)&lifc) < 0) {
337e11c3f44Smeem 		logperror("initifs: ioctl (get interface configuration)");
3387c478bd9Sstevel@tonic-gate 		free(buf);
3397c478bd9Sstevel@tonic-gate 		return;
3407c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 	/*
343e11c3f44Smeem 	 * If every lifr_req slot is taken, then additional interfaces must
344e11c3f44Smeem 	 * have been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
345e11c3f44Smeem 	 * Recalculate to make sure we didn't miss any interfaces.
3467c478bd9Sstevel@tonic-gate 	 */
347e11c3f44Smeem 	nlifr = lifc.lifc_len / sizeof (struct lifreq);
348e11c3f44Smeem 	if (nlifr >= lifn.lifn_count) {
349e11c3f44Smeem 		free(buf);
350e11c3f44Smeem 		goto again;
351e11c3f44Smeem 	}
353e11c3f44Smeem 	/*
354e11c3f44Smeem 	 * Walk through the lifreqs returned by SIOGGLIFCONF, and refresh the
355e11c3f44Smeem 	 * global list of addresses, phyint groups, phyints, and logints.
356e11c3f44Smeem 	 */
357e11c3f44Smeem 	for (lifr = lifc.lifc_req, i = 0; i < nlifr; i++, lifr++) {
3587c478bd9Sstevel@tonic-gate 		af = lifr->lifr_addr.ss_family;
35987e66ffcSrk 		sockfd = (af == AF_INET) ? ifsock_v4 : ifsock_v6;
360e11c3f44Smeem 		(void) strlcpy(lifreq.lifr_name, lifr->lifr_name, LIFNAMSIZ);
36287e66ffcSrk 		if (ioctl(sockfd, SIOCGLIFFLAGS, &lifreq) == -1) {
36387e66ffcSrk 			if (errno != ENXIO)
36487e66ffcSrk 				logperror("initifs: ioctl (SIOCGLIFFLAGS)");
36587e66ffcSrk 			continue;
36687e66ffcSrk 		}
367e11c3f44Smeem 		flags = lifreq.lifr_flags;
369e11c3f44Smeem 		/*
370e11c3f44Smeem 		 * If the address is IFF_UP, add it to the local address list.
371e11c3f44Smeem 		 * (We ignore addresses that aren't IFF_UP since another node
372e11c3f44Smeem 		 * might legitimately have that address IFF_UP.)
373e11c3f44Smeem 		 */
374e11c3f44Smeem 		if (flags & IFF_UP) {
375e11c3f44Smeem 			(void) addrlist_add(&localaddrs, lifr->lifr_name, flags,
376e11c3f44Smeem 			    &lifr->lifr_addr);
377e11c3f44Smeem 		}
37987e66ffcSrk 		/*
380e11c3f44Smeem 		 * If this address is on an IPMP meta-interface, update our
381e11c3f44Smeem 		 * phyint_group information (either by recording that group
382e11c3f44Smeem 		 * still exists or creating a new group), and track what
383e11c3f44Smeem 		 * group the address is part of.
38487e66ffcSrk 		 */
385e11c3f44Smeem 		if (flags & IFF_IPMP) {
386e11c3f44Smeem 			if (ioctl(sockfd, SIOCGLIFGROUPNAME, &lifreq) == -1) {
387e11c3f44Smeem 				if (errno != ENXIO)
388e11c3f44Smeem 					logperror("initifs: ioctl "
389e11c3f44Smeem 					    "(SIOCGLIFGROUPNAME)");
39087e66ffcSrk 				continue;
39187e66ffcSrk 			}
393e11c3f44Smeem 			pg = phyint_group_lookup(lifreq.lifr_groupname);
394e11c3f44Smeem 			if (pg == NULL) {
395e11c3f44Smeem 				pg = phyint_group_create(lifreq.lifr_groupname);
396e11c3f44Smeem 				if (pg == NULL) {
397e11c3f44Smeem 					logerr("initifs: cannot create group "