diff options
author | vi117747 <none@none> | 2007-05-24 12:17:11 -0700 |
---|---|---|
committer | vi117747 <none@none> | 2007-05-24 12:17:11 -0700 |
commit | 1d19ca101f1c458100349d59ba2d115d8e2c6f9d (patch) | |
tree | 2ed84c4bcd25a695a624f77a879e9adfa1433502 | |
parent | 9c7f0c7949f4f8c13342ed0167ea42f8d77b5f21 (diff) | |
download | illumos-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.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip_if.c | 3 | ||||
-rw-r--r-- | usr/src/uts/common/inet/sctp/sctp_addr.c | 99 | ||||
-rw-r--r-- | usr/src/uts/common/inet/sctp/sctp_addr.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/inet/sctp/sctp_input.c | 1 | ||||
-rw-r--r-- | usr/src/uts/common/inet/sctp_ip.h | 10 | ||||
-rw-r--r-- | usr/src/uts/common/inet/tcp/tcp.c | 9 | ||||
-rw-r--r-- | usr/src/uts/common/inet/tcp_impl.h | 35 | ||||
-rw-r--r-- | usr/src/uts/common/net/if.h | 4 |
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) |