aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2007-02-21 05:06:04 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-02-26 14:42:49 -0500
commit8c4a2d41a7eb5a8f214f537acca533dcd6430782 (patch)
tree48081d53d976bcb69da509c63d5bfb733a27446a /net
parent2c4f6219aca5939b57596278ea8b014275d4917b (diff)
[SCTP]: Fix connection hang/slowdown with PR-SCTP
The problem that this patch corrects happens when all of the following conditions are satisfisfied: 1. PR-SCTP is used and the timeout on the chunks is set below RTO.Max. 2. One of the paths on a multihomed associations is brought down. In this scenario, data will expire within the rto of the initial transmission and will never be retransmitted. However this data still fills the send buffer and is counted against the association as outstanding data. This causes any new data not to be sent and retransmission to not happen. The fix is to discount the abandoned data from the outstanding count and peers rwnd estimation. This allows new data to be sent and a retransmission timer restarted. Even though this new data will most likely expire within the rto, the timer still counts as a strike against the transport and forces the FORWARD-TSN chunk to be retransmitted as well. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: Sridhar Samudrala <sri@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/outqueue.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 5c2ddd10db06..41abfd17627e 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -396,6 +396,19 @@ void sctp_retransmit_mark(struct sctp_outq *q,
396 if (sctp_chunk_abandoned(chunk)) { 396 if (sctp_chunk_abandoned(chunk)) {
397 list_del_init(lchunk); 397 list_del_init(lchunk);
398 sctp_insert_list(&q->abandoned, lchunk); 398 sctp_insert_list(&q->abandoned, lchunk);
399
400 /* If this chunk has not been previousely acked,
401 * stop considering it 'outstanding'. Our peer
402 * will most likely never see it since it will
403 * not be retransmitted
404 */
405 if (!chunk->tsn_gap_acked) {
406 chunk->transport->flight_size -=
407 sctp_data_size(chunk);
408 q->outstanding_bytes -= sctp_data_size(chunk);
409 q->asoc->peer.rwnd += (sctp_data_size(chunk) +
410 sizeof(struct sk_buff));
411 }
399 continue; 412 continue;
400 } 413 }
401 414
@@ -1244,6 +1257,15 @@ static void sctp_check_transmitted(struct sctp_outq *q,
1244 if (sctp_chunk_abandoned(tchunk)) { 1257 if (sctp_chunk_abandoned(tchunk)) {
1245 /* Move the chunk to abandoned list. */ 1258 /* Move the chunk to abandoned list. */
1246 sctp_insert_list(&q->abandoned, lchunk); 1259 sctp_insert_list(&q->abandoned, lchunk);
1260
1261 /* If this chunk has not been acked, stop
1262 * considering it as 'outstanding'.
1263 */
1264 if (!tchunk->tsn_gap_acked) {
1265 tchunk->transport->flight_size -=
1266 sctp_data_size(tchunk);
1267 q->outstanding_bytes -= sctp_data_size(tchunk);
1268 }
1247 continue; 1269 continue;
1248 } 1270 }
1249 1271
@@ -1695,11 +1717,6 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
1695 */ 1717 */
1696 if (TSN_lte(tsn, ctsn)) { 1718 if (TSN_lte(tsn, ctsn)) {
1697 list_del_init(lchunk); 1719 list_del_init(lchunk);
1698 if (!chunk->tsn_gap_acked) {
1699 chunk->transport->flight_size -=
1700 sctp_data_size(chunk);
1701 q->outstanding_bytes -= sctp_data_size(chunk);
1702 }
1703 sctp_chunk_free(chunk); 1720 sctp_chunk_free(chunk);
1704 } else { 1721 } else {
1705 if (TSN_lte(tsn, asoc->adv_peer_ack_point+1)) { 1722 if (TSN_lte(tsn, asoc->adv_peer_ack_point+1)) {