17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5921e7e07Smeem  * Common Development and Distribution License (the "License").
6921e7e07Smeem  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22e11c3f44Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate #include "mpd_defs.h"
277c478bd9Sstevel@tonic-gate #include "mpd_tables.h"
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Global list of phyints, phyint instances, phyint groups and the anonymous
317c478bd9Sstevel@tonic-gate  * group; the latter is initialized in phyint_init().
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate struct phyint *phyints = NULL;
347c478bd9Sstevel@tonic-gate struct phyint_instance	*phyint_instances = NULL;
357c478bd9Sstevel@tonic-gate struct phyint_group *phyint_groups = NULL;
367c478bd9Sstevel@tonic-gate struct phyint_group *phyint_anongroup;
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * Grouplist signature; initialized in phyint_init().
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate static uint64_t phyint_grouplistsig;
437c478bd9Sstevel@tonic-gate static void phyint_inst_insert(struct phyint_instance *pii);
447c478bd9Sstevel@tonic-gate static void phyint_inst_print(struct phyint_instance *pii);
467c478bd9Sstevel@tonic-gate static void phyint_insert(struct phyint *pi, struct phyint_group *pg);
477c478bd9Sstevel@tonic-gate static void phyint_delete(struct phyint *pi);
48e11c3f44Smeem static boolean_t phyint_is_usable(struct phyint *pi);
507c478bd9Sstevel@tonic-gate static void logint_print(struct logint *li);
517c478bd9Sstevel@tonic-gate static void logint_insert(struct phyint_instance *pii, struct logint *li);
527c478bd9Sstevel@tonic-gate static struct logint *logint_lookup(struct phyint_instance *pii, char *li_name);
547c478bd9Sstevel@tonic-gate static void target_print(struct target *tg);
557c478bd9Sstevel@tonic-gate static void target_insert(struct phyint_instance *pii, struct target *tg);
567c478bd9Sstevel@tonic-gate static struct target *target_first(struct phyint_instance *pii);
577c478bd9Sstevel@tonic-gate static struct target *target_select_best(struct phyint_instance *pii);
587c478bd9Sstevel@tonic-gate static void target_flush_hosts(struct phyint_group *pg);
607c478bd9Sstevel@tonic-gate static void reset_pii_probes(struct phyint_instance *pii, struct target *tg);
627c478bd9Sstevel@tonic-gate static boolean_t phyint_inst_v6_sockinit(struct phyint_instance *pii);
637c478bd9Sstevel@tonic-gate static boolean_t phyint_inst_v4_sockinit(struct phyint_instance *pii);
657c478bd9Sstevel@tonic-gate static int phyint_state_event(struct phyint_group *pg, struct phyint *pi);
667c478bd9Sstevel@tonic-gate static int phyint_group_state_event(struct phyint_group *pg);
677c478bd9Sstevel@tonic-gate static int phyint_group_change_event(struct phyint_group *pg, ipmp_group_op_t);
687c478bd9Sstevel@tonic-gate static int phyint_group_member_event(struct phyint_group *pg, struct phyint *pi,
697c478bd9Sstevel@tonic-gate     ipmp_if_op_t op);
71e11c3f44Smeem static int logint_upcount(struct phyint *pi);
727c478bd9Sstevel@tonic-gate static uint64_t gensig(void);
747c478bd9Sstevel@tonic-gate /* Initialize any per-file global state.  Returns 0 on success, -1 on failure */
757c478bd9Sstevel@tonic-gate int
phyint_init(void)767c478bd9Sstevel@tonic-gate phyint_init(void)
777c478bd9Sstevel@tonic-gate {
787c478bd9Sstevel@tonic-gate 	phyint_grouplistsig = gensig();
797c478bd9Sstevel@tonic-gate 	if (track_all_phyints) {
807c478bd9Sstevel@tonic-gate 		phyint_anongroup = phyint_group_create("");
817c478bd9Sstevel@tonic-gate 		if (phyint_anongroup == NULL)
827c478bd9Sstevel@tonic-gate 			return (-1);
837c478bd9Sstevel@tonic-gate 		phyint_group_insert(phyint_anongroup);
847c478bd9Sstevel@tonic-gate 	}
857c478bd9Sstevel@tonic-gate 	return (0);
867c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate /* Return the phyint with the given name */
897c478bd9Sstevel@tonic-gate struct phyint *
phyint_lookup(const char * name)907c478bd9Sstevel@tonic-gate phyint_lookup(const char *name)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	struct phyint *pi;
947c478bd9Sstevel@tonic-gate 	if (debug & D_PHYINT)
957c478bd9Sstevel@tonic-gate 		logdebug("phyint_lookup(%s)\n", name);
977c478bd9Sstevel@tonic-gate 	for (pi = phyints; pi != NULL; pi = pi->pi_next) {
987c478bd9Sstevel@tonic-gate 		if (strncmp(pi->pi_name, name, sizeof (pi->pi_name)) == 0)
997c478bd9Sstevel@tonic-gate 			break;
1007c478bd9Sstevel@tonic-gate 	}
1017c478bd9Sstevel@tonic-gate 	return (pi);
1027c478bd9Sstevel@tonic-gate }
104e11c3f44Smeem /*
105e11c3f44Smeem  * Lookup a phyint in the group that has the same hardware address as `pi', or
106e11c3f44Smeem  * NULL if there's none.  If `online_only' is set, then only online phyints
107e11c3f44Smeem  * are considered when matching.  Otherwise, phyints that had been offlined
108e11c3f44Smeem  * due to a duplicate hardware address will also be considered.
109e11c3f44Smeem  */
110e11c3f44Smeem static struct phyint *
phyint_lookup_hwaddr(struct phyint * pi,boolean_t online_only)111e11c3f44Smeem phyint_lookup_hwaddr(struct phyint *pi, boolean_t online_only)
112e11c3f44Smeem {
113e11c3f44Smeem 	struct phyint *pi2;
115e11c3f44Smeem 	if (pi->pi_group == phyint_anongroup)
116e11c3f44Smeem 		return (NULL);
118e11c3f44Smeem 	for (pi2 = pi->pi_group->pg_phyint; pi2 != NULL; pi2 = pi2->pi_pgnext) {
119e11c3f44Smeem 		if (pi2 == pi)
120e11c3f44Smeem 			continue;
122e11c3f44Smeem 		/*
123e11c3f44Smeem 		 * NOTE: even when online_only is B_FALSE, we ignore phyints
124e11c3f44Smeem 		 * that are administratively offline (rather than offline
125e11c3f44Smeem 		 * because they're dups); when they're brought back online,
126e11c3f44Smeem 		 * they'll be flagged as dups if need be.
127e11c3f44Smeem 		 */
128e11c3f44Smeem 		if (pi2->pi_state == PI_OFFLINE &&
129e11c3f44Smeem 		    (online_only || !pi2->pi_hwaddrdup))
130e11c3f44Smeem 			continue;
132e11c3f44Smeem 		if (pi2->pi_hwaddrlen == pi->pi_hwaddrlen &&
133e11c3f44Smeem 		    bcmp(pi2->pi_hwaddr, pi->pi_hwaddr, pi->pi_hwaddrlen) == 0)
134e11c3f44Smeem 			return (pi2);
135e11c3f44Smeem 	}
136e11c3f44Smeem 	return (NULL);
137e11c3f44Smeem }
139e11c3f44Smeem /*
140e11c3f44Smeem  * Respond to DLPI notifications.  Currently, this only processes physical
141e11c3f44Smeem  * address changes for the phyint passed via `arg' by onlining or offlining
142e11c3f44Smeem  * phyints in the group.
143e11c3f44Smeem  */
144e11c3f44Smeem /* ARGSUSED */
145e11c3f44Smeem static void
phyint_link_notify(dlpi_handle_t dh,dlpi_notifyinfo_t * dnip,void * arg)146e11c3f44Smeem phyint_link_notify(dlpi_handle_t dh, dlpi_notifyinfo_t *dnip, void *arg)
147e11c3f44Smeem {
148e11c3f44Smeem 	struct phyint *pi = arg;
149e11c3f44Smeem 	struct phyint *oduppi = NULL, *duppi = NULL;
151e11c3f44Smeem 	assert((dnip->dni_note & pi->pi_notes) != 0);
153e11c3f44Smeem 	if (dnip->dni_note != DL_NOTE_PHYS_ADDR)
154e11c3f44Smeem 		return;
156e11c3f44Smeem 	assert(dnip->dni_physaddrlen <= DLPI_PHYSADDR_MAX);
158e11c3f44Smeem 	/*
159e11c3f44Smeem 	 * If our hardware address hasn't changed, there's nothing to do.
160e11c3f44Smeem 	 */
161e11c3f44Smeem 	if (pi->pi_hwaddrlen == dnip->dni_physaddrlen &&
162e11c3f44Smeem 	    bcmp(pi->pi_hwaddr, dnip->dni_physaddr, pi->pi_hwaddrlen) == 0)
163e11c3f44Smeem 		return;
165e11c3f44Smeem 	oduppi = phyint_lookup_hwaddr(pi, _B_FALSE);
166e11c3f44Smeem 	pi->pi_hwaddrlen = dnip->dni_physaddrlen;
167e11c3f44Smeem 	(void) memcpy(pi->pi_hwaddr, dnip->dni_physaddr, pi->pi_hwaddrlen);
168e11c3f44Smeem 	duppi = phyint_lookup_hwaddr(pi, _B_FALSE);
170e11c3f44Smeem 	if (oduppi != NULL || pi->pi_hwaddrdup) {
171e11c3f44Smeem 		/*
172e11c3f44Smeem 		 * Our old hardware address was a duplicate.  If we'd been
173e11c3f44Smeem 		 * offlined because of it, and our new hardware address is not
174e11c3f44Smeem 		 * a duplicate, then bring us online.  Otherwise, `oduppi'
175e11c3f44Smeem 		 * must've been the one brought offline; bring it online.
176e11c3f44Smeem 		 */
177e11c3f44Smeem 		if (pi->pi_hwaddrdup) {
178e11c3f44Smeem 			if (duppi == NULL)
179e11c3f44Smeem 				(void) phyint_undo_offline(pi);
180e11c3f44Smeem 		} else {
181e11c3f44Smeem 			assert(oduppi->pi_hwaddrdup);
182e11c3f44Smeem 			(void) phyint_undo_offline(oduppi);
183e11c3f44Smeem 		}
184e11c3f44Smeem 	}
186e11c3f44Smeem 	if (duppi != NULL && !pi->pi_hwaddrdup) {
187e11c3f44Smeem 		/*
188e11c3f44Smeem 		 * Our new hardware address was a duplicate and we're not
189e11c3f44Smeem 		 * yet flagged as a duplicate; bring us offline.
190e11c3f44Smeem 		 */
191e11c3f44Smeem 		pi->pi_hwaddrdup = _B_TRUE;
192e11c3f44Smeem 		(void) phyint_offline(pi, 0);
193e11c3f44Smeem 	}
194e11c3f44Smeem }
196e11c3f44Smeem /*
197e11c3f44Smeem  * Initialize information about the underlying link for `pi', and set us