changeset 4311:27c974ce5d7f

6349696 PANIC: assertion failed: peer_tcp->tcp_loopback && peer_tcp->tcp_loopback_peer == NULL 6350527 assertion failed: !(flags & > >>TH_MARKNEXT_NEEDED), file: ../../common/inet/tcp/tcp.c 6531423 SCTP_IPIF_INSERT is adrift 6539189 IFF_COS_ENABLED can be changed by SIOCS[L]IFFLAGS 6546661 sctp_update_ipif_addr() panics if passed an ipif tied to an unknown ill 6546662 sctp's ill caching cannot handle interface index changes 6553898 Page fault during multithreaded SCTP stress test
author vi117747
date Thu, 24 May 2007 12:17:11 -0700
parents 127d7ee782ad
children 4fef416ca8cb
files usr/src/uts/common/inet/ip/ip.c usr/src/uts/common/inet/ip/ip_if.c usr/src/uts/common/inet/sctp/sctp_addr.c usr/src/uts/common/inet/sctp/sctp_addr.h usr/src/uts/common/inet/sctp/sctp_input.c usr/src/uts/common/inet/sctp_ip.h usr/src/uts/common/inet/tcp/tcp.c usr/src/uts/common/inet/tcp_impl.h usr/src/uts/common/net/if.h
diffstat 9 files changed, 131 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip/ip.c	Thu May 24 12:06:56 2007 -0700
+++ b/usr/src/uts/common/inet/ip/ip.c	Thu May 24 12:17:11 2007 -0700
@@ -20658,6 +20658,8 @@
 		if (CONN_CACHE_IRE(connp) && connp->conn_ire_cache == NULL) {
 			rw_enter(&ire->ire_bucket->irb_lock, RW_READER);
 			if (!(ire->ire_marks & IRE_MARK_CONDEMNED)) {
+				if (connp->conn_ulp == IPPROTO_TCP)
+					TCP_CHECK_IREINFO(connp->conn_tcp, ire);
 				connp->conn_ire_cache = ire;
 				cached = B_TRUE;
 			}
--- a/usr/src/uts/common/inet/ip/ip_if.c	Thu May 24 12:06:56 2007 -0700
+++ b/usr/src/uts/common/inet/ip/ip_if.c	Thu May 24 12:17:11 2007 -0700
@@ -22278,6 +22278,9 @@
 
 	phyi->phyint_ifindex = index;
 
+	/* Update SCTP's ILL list */
+	sctp_ill_reindex(ill, old_index);
+
 	connc.cc_old_ifindex = old_index;
 	connc.cc_new_ifindex = index;
 	ip_change_ifindex(ill, &connc);
--- a/usr/src/uts/common/inet/sctp/sctp_addr.c	Thu May 24 12:06:56 2007 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_addr.c	Thu May 24 12:17:11 2007 -0700
@@ -28,6 +28,7 @@
 #include <sys/types.h>
 #include <sys/systm.h>
 #include <sys/stream.h>
+#include <sys/cmn_err.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
 #include <sys/kmem.h>
@@ -53,28 +54,12 @@
 			    zoneid_t, boolean_t, uint_t, uint_t, boolean_t,
 			    sctp_stack_t *);
 static int		sctp_get_all_ipifs(sctp_t *, int);
-int			sctp_valid_addr_list(sctp_t *, const void *, uint32_t,
-			    uchar_t *, size_t);
 static int		sctp_ipif_hash_insert(sctp_t *, sctp_ipif_t *, int,
 			    boolean_t, boolean_t);
 static void		sctp_ipif_hash_remove(sctp_t *, sctp_ipif_t *);
 static int		sctp_compare_ipif_list(sctp_ipif_hash_t *,
 			    sctp_ipif_hash_t *);
-int			sctp_compare_saddrs(sctp_t *, sctp_t *);
 static int		sctp_copy_ipifs(sctp_ipif_hash_t *, sctp_t *, int);
-int			sctp_dup_saddrs(sctp_t *, sctp_t *, int);
-void			sctp_free_saddrs(sctp_t *);
-void			sctp_update_ill(ill_t *, int);
-void			sctp_update_ipif(ipif_t *, int);
-void			sctp_move_ipif(ipif_t *, ill_t *, ill_t *);
-void			sctp_del_saddr(sctp_t *, sctp_saddr_ipif_t *);
-void			sctp_del_saddr_list(sctp_t *, const void *, int,
-			    boolean_t);
-sctp_saddr_ipif_t	*sctp_saddr_lookup(sctp_t *, in6_addr_t *, uint_t);
-in6_addr_t		sctp_get_valid_addr(sctp_t *, boolean_t);
-int			sctp_getmyaddrs(void *, void *, int *);
-void			sctp_saddr_init(sctp_stack_t *);
-void			sctp_saddr_fini(sctp_stack_t *);
 
 #define	SCTP_ADDR4_HASH(addr)	\
 	(((addr) ^ ((addr) >> 8) ^ ((addr) >> 16) ^ ((addr) >> 24)) &	\
@@ -670,8 +655,10 @@
 	index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
 	sctp_ill = list_head(&sctps->sctps_g_ills[index].sctp_ill_list);
 	for (i = 0; i < sctps->sctps_g_ills[index].ill_count; i++) {
-		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill))
+		if ((sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill)) &&
+		    (sctp_ill->sctp_ill_isv6 == ill->ill_isv6)) {
 			break;
+		}
 		sctp_ill = list_next(&sctps->sctps_g_ills[index].sctp_ill_list,
 		    sctp_ill);
 	}
@@ -688,14 +675,16 @@
 		sctp_ill = kmem_zalloc(sizeof (sctp_ill_t), KM_NOSLEEP);
 		/* Need to re-try? */
 		if (sctp_ill == NULL) {
-			ip1dbg(("sctp_ill_insert: mem error..\n"));
+			cmn_err(CE_WARN, "sctp_update_ill: error adding "
+			    "ILL %p to SCTP's ILL list", (void *)ill);
 			rw_exit(&sctps->sctps_g_ills_lock);
 			return;
 		}
 		sctp_ill->sctp_ill_name = kmem_zalloc(ill->ill_name_length,
 		    KM_NOSLEEP);
 		if (sctp_ill->sctp_ill_name == NULL) {
-			ip1dbg(("sctp_ill_insert: mem error..\n"));
+			cmn_err(CE_WARN, "sctp_update_ill: error adding "
+			    "ILL %p to SCTP's ILL list", (void *)ill);
 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
 			rw_exit(&sctps->sctps_g_ills_lock);
 			return;
@@ -706,6 +695,7 @@
 		sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
 		sctp_ill->sctp_ill_flags = ill->ill_phyint->phyint_flags;
 		sctp_ill->sctp_ill_netstack = ns;	/* No netstack_hold */
+		sctp_ill->sctp_ill_isv6 = ill->ill_isv6;
 		list_insert_tail(&sctps->sctps_g_ills[index].sctp_ill_list,
 		    (void *)sctp_ill);
 		sctps->sctps_g_ills[index].ill_count++;
@@ -736,6 +726,55 @@
 	rw_exit(&sctps->sctps_g_ills_lock);
 }
 
+/*
+ * The ILL's index is being changed, just remove it from the old list,
+ * change the SCTP ILL's index and re-insert using the new index.
+ */
+void
+sctp_ill_reindex(ill_t *ill, uint_t orig_ill_index)
+{
+	sctp_ill_t	*sctp_ill = NULL;
+	sctp_ill_t	*nxt_sill;
+	uint_t		indx;
+	uint_t		nindx;
+	boolean_t	once = B_FALSE;
+	netstack_t	*ns = ill->ill_ipst->ips_netstack;
+	sctp_stack_t	*sctps = ns->netstack_sctp;
+
+	rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
+
+	indx = SCTP_ILL_HASH_FN(orig_ill_index);
+	nindx = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
+	sctp_ill = list_head(&sctps->sctps_g_ills[indx].sctp_ill_list);
+	while (sctp_ill != NULL) {
+		nxt_sill = list_next(&sctps->sctps_g_ills[indx].sctp_ill_list,
+		    sctp_ill);
+		if (sctp_ill->sctp_ill_index == orig_ill_index) {
+			sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
+			/*
+			 * if the new index hashes to the same value, all's
+			 * done.
+			 */
+			if (nindx != indx) {
+				list_remove(
+				    &sctps->sctps_g_ills[indx].sctp_ill_list,
+				    (void *)sctp_ill);
+				sctps->sctps_g_ills[indx].ill_count--;
+				list_insert_tail(
+				    &sctps->sctps_g_ills[nindx].sctp_ill_list,
+				    (void *)sctp_ill);
+				sctps->sctps_g_ills[nindx].ill_count++;
+			}
+			if (once)
+				break;
+			/* We might have one for v4 and for v6 */
+			once = B_TRUE;
+		}
+		sctp_ill = nxt_sill;
+	}
+	rw_exit(&sctps->sctps_g_ills_lock);
+}
+
 /* move ipif from f_ill to t_ill */
 void
 sctp_move_ipif(ipif_t *ipif, ill_t *f_ill, ill_t *t_ill)
@@ -754,8 +793,10 @@
 	hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(f_ill));
 	fsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
 	for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
-		if (fsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(f_ill))
+		if (fsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(f_ill) &&
+		    fsctp_ill->sctp_ill_isv6 == f_ill->ill_isv6) {
 			break;
+		}
 		fsctp_ill = list_next(
 		    &sctps->sctps_g_ills[hindex].sctp_ill_list, fsctp_ill);
 	}
@@ -763,8 +804,10 @@
 	hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(t_ill));
 	tsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
 	for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
-		if (tsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(t_ill))
+		if (tsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(t_ill) &&
+		    tsctp_ill->sctp_ill_isv6 == t_ill->ill_isv6) {
 			break;
+		}
 		tsctp_ill = list_next(
 		    &sctps->sctps_g_ills[hindex].sctp_ill_list, tsctp_ill);
 	}
@@ -937,16 +980,19 @@
 	ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
 	sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
 	for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
-		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill))
+		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
+		    sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
 			break;
+		}
 		sctp_ill = list_next(
 		    &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
 	}
 
 	if (sctp_ill == NULL) {
-		ip1dbg(("sctp_ipif_insert: ill not found ..\n"));
+		ip1dbg(("sctp_update_ipif_addr: ill not found ..\n"));
 		rw_exit(&sctps->sctps_g_ipifs_lock);
 		rw_exit(&sctps->sctps_g_ills_lock);
+		return;
 	}
 
 	if (osctp_ipif != NULL) {
@@ -1005,7 +1051,8 @@
 	sctp_ipif = kmem_zalloc(sizeof (sctp_ipif_t), KM_NOSLEEP);
 	/* Try again? */
 	if (sctp_ipif == NULL) {
-		ip1dbg(("sctp_ipif_insert: mem failure..\n"));
+		cmn_err(CE_WARN, "sctp_update_ipif_addr: error adding "
+		    "IPIF %p to SCTP's IPIF list", (void *)ipif);
 		rw_exit(&sctps->sctps_g_ipifs_lock);
 		rw_exit(&sctps->sctps_g_ills_lock);
 		return;
@@ -1057,8 +1104,10 @@
 	ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
 	sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
 	for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
-		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill))
+		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
+		    sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
 			break;
+		}
 		sctp_ill = list_next(
 		    &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
 	}
--- a/usr/src/uts/common/inet/sctp/sctp_addr.h	Thu May 24 12:06:56 2007 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_addr.h	Thu May 24 12:17:11 2007 -0700
@@ -116,6 +116,7 @@
 	uint32_t	sctp_ill_ipifcnt;
 	uint_t		sctp_ill_index;
 	uint64_t	sctp_ill_flags;
+	boolean_t	sctp_ill_isv6;
 	netstack_t	*sctp_ill_netstack; /* Does not have a netstack_hold */
 } sctp_ill_t;
 
@@ -152,9 +153,6 @@
 #define	SCTP_ADDR_OVERLAP	3
 #define	SCTP_ADDR_DISJOINT	4
 
-extern void		sctp_update_ill(ill_t *, int);
-extern void		sctp_update_ipif(ipif_t *, int);
-
 extern int		sctp_valid_addr_list(sctp_t *, const void *, uint32_t,
 			    uchar_t *, size_t);
 extern int		sctp_dup_saddrs(sctp_t *, sctp_t *, int);
--- a/usr/src/uts/common/inet/sctp/sctp_input.c	Thu May 24 12:06:56 2007 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_input.c	Thu May 24 12:17:11 2007 -0700
@@ -2866,6 +2866,7 @@
 		}
 		fp->acked = 0;
 	}
+	fp = sctp->sctp_current;
 check_ss_rxmit:
 	/*
 	 * If this is a SACK following a timeout, check if there are
--- a/usr/src/uts/common/inet/sctp_ip.h	Thu May 24 12:06:56 2007 -0700
+++ b/usr/src/uts/common/inet/sctp_ip.h	Thu May 24 12:17:11 2007 -0700
@@ -79,14 +79,14 @@
 extern void sctp_update_ipif(ipif_t *, int);
 extern void sctp_move_ipif(ipif_t *, ill_t *, ill_t *);
 extern void sctp_update_ipif_addr(ipif_t *, in6_addr_t);
+extern void sctp_ill_reindex(ill_t *, uint_t);
 
 #define	SCTP_ILL_INSERT		1
 #define	SCTP_ILL_REMOVE		2
-#define	SCTP_IPIF_INSERT	3
-#define	SCTP_IPIF_REMOVE	4
-#define	SCTP_IPIF_UP		5
-#define	SCTP_IPIF_DOWN		6
-#define	SCTP_IPIF_UPDATE	7
+#define	SCTP_IPIF_REMOVE	3
+#define	SCTP_IPIF_UP		4
+#define	SCTP_IPIF_DOWN		5
+#define	SCTP_IPIF_UPDATE	6
 
 /* IP routines for SCTP to call. */
 extern void ip_fanout_sctp_raw(mblk_t *, ill_t *, ipha_t *, boolean_t,
--- a/usr/src/uts/common/inet/tcp/tcp.c	Thu May 24 12:06:56 2007 -0700
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Thu May 24 12:17:11 2007 -0700
@@ -12914,6 +12914,12 @@
 		 * the connection has been accept()ed since it can't
 		 * buffer OOB data.  Discard segment if this happens.
 		 *
+		 * We can't just rely on a non-null tcp_listener to indicate
+		 * that the accept() has completed since unlinking of the
+		 * eager and completion of the accept are not atomic.
+		 * tcp_detached, when it is not set (B_FALSE) indicates
+		 * that the accept() has completed.
+		 *
 		 * Nor can it reassemble urgent pointers, so discard
 		 * if it's not the next segment expected.
 		 *
@@ -12922,7 +12928,7 @@
 		 * data, and new data all are in the same mblk.
 		 */
 		ASSERT(mp != NULL);
-		if (tcp->tcp_listener || !pullupmsg(mp, -1)) {
+		if (tcp->tcp_detached || !pullupmsg(mp, -1)) {
 			freemsg(mp);
 			return;
 		}
@@ -18769,6 +18775,7 @@
 		if (CONN_CACHE_IRE(connp)) {
 			rw_enter(&ire->ire_bucket->irb_lock, RW_READER);
 			if (!(ire->ire_marks & IRE_MARK_CONDEMNED)) {
+				TCP_CHECK_IREINFO(tcp, ire);
 				connp->conn_ire_cache = ire;
 				cached = B_TRUE;
 			}
--- a/usr/src/uts/common/inet/tcp_impl.h	Thu May 24 12:06:56 2007 -0700
+++ b/usr/src/uts/common/inet/tcp_impl.h	Thu May 24 12:17:11 2007 -0700
@@ -109,6 +109,41 @@
 }
 
 /*
+ * Before caching the conn IRE, we need to make sure certain TCP
+ * states are in sync with the ire. The mismatch could occur if the
+ * TCP state has been set in tcp_adapt_ire() using a different IRE,
+ * e.g if an address was not present during an initial connect(),
+ * tcp_adapt_ire() will set the state using the interface route.
+ * Subsequently, if the address is added to the local machine, the
+ * retransmitted SYN will get the correct (loopback) IRE, but the TCP
+ * state (tcp_loopback and tcp_localnet) will remain out of sync.
+ * This is especially an issue with TCP fusion which relies on the
+ * TCP state to be accurate.
+ *
+ * This check/change should be made only if the TCP is not yet in
+ * the established state, else it would lead to inconsistencies.
+ */
+#define	TCP_CHECK_IREINFO(tcp, ire) {					\
+	if ((tcp)->tcp_state < TCPS_ESTABLISHED) {			\
+		if (((ire)->ire_type & (IRE_LOOPBACK | 			\
+		    IRE_LOCAL)) && !(tcp)->tcp_loopback) {		\
+			(tcp)->tcp_loopback = B_TRUE;			\
+		} else if ((tcp)->tcp_loopback && 			\
+		    !((ire)->ire_type & (IRE_LOOPBACK | IRE_LOCAL))) {	\
+			(tcp)->tcp_loopback = B_FALSE;			\
+		}							\
+		if ((tcp)->tcp_ipversion == IPV4_VERSION) {		\
+			(tcp)->tcp_localnet =				\
+			    ((ire)->ire_gateway_addr == 0);		\
+		} else {						\
+			(tcp)->tcp_localnet =				\
+			    IN6_IS_ADDR_UNSPECIFIED(			\
+			    &(ire)->ire_gateway_addr_v6);		\
+		}							\
+	}								\
+}
+
+/*
  * Write-side flow-control is implemented via the per instance STREAMS
  * write-side Q by explicitly setting QFULL to stop the flow of mblk_t(s)
  * and clearing QFULL and calling qbackenable() to restart the flow based
--- a/usr/src/uts/common/net/if.h	Thu May 24 12:06:56 2007 -0700
+++ b/usr/src/uts/common/net/if.h	Thu May 24 12:17:11 2007 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -178,7 +178,7 @@
 	(IFF_BROADCAST | IFF_POINTOPOINT | IFF_RUNNING | IFF_PROMISC | \
 	IFF_MULTICAST | IFF_MULTI_BCAST | IFF_UNNUMBERED | IFF_IPV4 | \
 	IFF_IPV6 | IFF_INACTIVE | IFF_FIXEDMTU | IFF_VIRTUAL | \
-	IFF_LOOPBACK | IFF_ALLMULTI | IFF_DUPLICATE)
+	IFF_LOOPBACK | IFF_ALLMULTI | IFF_DUPLICATE | IFF_COS_ENABLED)
 
 /*
  * Output queues (ifp->if_snd) and internetwork datagram level (pup level 1)