summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvi117747 <none@none>2007-05-24 12:17:11 -0700
committervi117747 <none@none>2007-05-24 12:17:11 -0700
commit1d19ca101f1c458100349d59ba2d115d8e2c6f9d (patch)
tree2ed84c4bcd25a695a624f77a879e9adfa1433502
parent9c7f0c7949f4f8c13342ed0167ea42f8d77b5f21 (diff)
downloadillumos-joyent-1d19ca101f1c458100349d59ba2d115d8e2c6f9d.tar.gz
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
-rw-r--r--usr/src/uts/common/inet/ip/ip.c2
-rw-r--r--usr/src/uts/common/inet/ip/ip_if.c3
-rw-r--r--usr/src/uts/common/inet/sctp/sctp_addr.c99
-rw-r--r--usr/src/uts/common/inet/sctp/sctp_addr.h4
-rw-r--r--usr/src/uts/common/inet/sctp/sctp_input.c1
-rw-r--r--usr/src/uts/common/inet/sctp_ip.h10
-rw-r--r--usr/src/uts/common/inet/tcp/tcp.c9
-rw-r--r--usr/src/uts/common/inet/tcp_impl.h35
-rw-r--r--usr/src/uts/common/net/if.h4
9 files changed, 131 insertions, 36 deletions
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index 60dedabb18..aa2b0e3dc7 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -20658,6 +20658,8 @@ standard_path:
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;
}
diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c
index 16595a3c4d..87b826f40f 100644
--- a/usr/src/uts/common/inet/ip/ip_if.c
+++ b/usr/src/uts/common/inet/ip/ip_if.c
@@ -22278,6 +22278,9 @@ ip_sioctl_slifindex(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
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);
diff --git a/usr/src/uts/common/inet/sctp/sctp_addr.c b/usr/src/uts/common/inet/sctp/sctp_addr.c
index d181162fd3..80b100eaf1 100644
--- a/usr/src/uts/common/inet/sctp/sctp_addr.c
+++ b/usr/src/uts/common/inet/sctp/sctp_addr.c
@@ -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 @@ static sctp_ipif_t *sctp_lookup_ipif_addr(in6_addr_t *, boolean_t,
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 @@ sctp_update_ill(ill_t *ill, int op)
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_update_ill(ill_t *ill, int op)
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_update_ill(ill_t *ill, int op)
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 @@ sctp_update_ill(ill_t *ill, int op)
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 @@ sctp_move_ipif(ipif_t *ipif, ill_t *f_ill, ill_t *t_ill)
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 @@ sctp_move_ipif(ipif_t *ipif, ill_t *f_ill, ill_t *t_ill)
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 @@ sctp_update_ipif_addr(ipif_t *ipif, in6_addr_t v6addr)
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_update_ipif_addr(ipif_t *ipif, in6_addr_t v6addr)
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 @@ sctp_update_ipif(ipif_t *ipif, int op)
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);
}
diff --git a/usr/src/uts/common/inet/sctp/sctp_addr.h b/usr/src/uts/common/inet/sctp/sctp_addr.h
index 2625b2e06a..9159aac29d 100644
--- a/usr/src/uts/common/inet/sctp/sctp_addr.h
+++ b/usr/src/uts/common/inet/sctp/sctp_addr.h
@@ -116,6 +116,7 @@ typedef struct sctp_ill_s {
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 @@ typedef struct sctp_ill_hash_s {
#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);
diff --git a/usr/src/uts/common/inet/sctp/sctp_input.c b/usr/src/uts/common/inet/sctp/sctp_input.c
index 6a5f1ef965..80e28152e0 100644
--- a/usr/src/uts/common/inet/sctp/sctp_input.c
+++ b/usr/src/uts/common/inet/sctp/sctp_input.c
@@ -2866,6 +2866,7 @@ ret:
}
fp->acked = 0;
}
+ fp = sctp->sctp_current;
check_ss_rxmit:
/*
* If this is a SACK following a timeout, check if there are
diff --git a/usr/src/uts/common/inet/sctp_ip.h b/usr/src/uts/common/inet/sctp_ip.h
index 567a600671..16ab99abab 100644
--- a/usr/src/uts/common/inet/sctp_ip.h
+++ b/usr/src/uts/common/inet/sctp_ip.h
@@ -79,14 +79,14 @@ extern void sctp_update_ill(ill_t *, int);
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,
diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c
index 356cbd279c..23eaaf43cf 100644
--- a/usr/src/uts/common/inet/tcp/tcp.c
+++ b/usr/src/uts/common/inet/tcp/tcp.c
@@ -12914,6 +12914,12 @@ tcp_rput_data(void *arg, mblk_t *mp, void *arg2)
* 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 @@ tcp_rput_data(void *arg, mblk_t *mp, void *arg2)
* 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 @@ tcp_send_find_ire(tcp_t *tcp, ipaddr_t *dst, ire_t **irep)
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;
}
diff --git a/usr/src/uts/common/inet/tcp_impl.h b/usr/src/uts/common/inet/tcp_impl.h
index 2f31dc531a..cfbbe84e3a 100644
--- a/usr/src/uts/common/inet/tcp_impl.h
+++ b/usr/src/uts/common/inet/tcp_impl.h
@@ -109,6 +109,41 @@ extern "C" {
}
/*
+ * 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
diff --git a/usr/src/uts/common/net/if.h b/usr/src/uts/common/net/if.h
index b4454bb645..2d4b5845b7 100644
--- a/usr/src/uts/common/net/if.h
+++ b/usr/src/uts/common/net/if.h
@@ -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 @@ struct ifnet {
(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)