[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>
This commit is contained in:
parent
2c4f6219ac
commit
8c4a2d41a7
1 changed files with 22 additions and 5 deletions
|
@ -396,6 +396,19 @@ void sctp_retransmit_mark(struct sctp_outq *q,
|
|||
if (sctp_chunk_abandoned(chunk)) {
|
||||
list_del_init(lchunk);
|
||||
sctp_insert_list(&q->abandoned, lchunk);
|
||||
|
||||
/* If this chunk has not been previousely acked,
|
||||
* stop considering it 'outstanding'. Our peer
|
||||
* will most likely never see it since it will
|
||||
* not be retransmitted
|
||||
*/
|
||||
if (!chunk->tsn_gap_acked) {
|
||||
chunk->transport->flight_size -=
|
||||
sctp_data_size(chunk);
|
||||
q->outstanding_bytes -= sctp_data_size(chunk);
|
||||
q->asoc->peer.rwnd += (sctp_data_size(chunk) +
|
||||
sizeof(struct sk_buff));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1244,6 +1257,15 @@ static void sctp_check_transmitted(struct sctp_outq *q,
|
|||
if (sctp_chunk_abandoned(tchunk)) {
|
||||
/* Move the chunk to abandoned list. */
|
||||
sctp_insert_list(&q->abandoned, lchunk);
|
||||
|
||||
/* If this chunk has not been acked, stop
|
||||
* considering it as 'outstanding'.
|
||||
*/
|
||||
if (!tchunk->tsn_gap_acked) {
|
||||
tchunk->transport->flight_size -=
|
||||
sctp_data_size(tchunk);
|
||||
q->outstanding_bytes -= sctp_data_size(tchunk);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1695,11 +1717,6 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
|
|||
*/
|
||||
if (TSN_lte(tsn, ctsn)) {
|
||||
list_del_init(lchunk);
|
||||
if (!chunk->tsn_gap_acked) {
|
||||
chunk->transport->flight_size -=
|
||||
sctp_data_size(chunk);
|
||||
q->outstanding_bytes -= sctp_data_size(chunk);
|
||||
}
|
||||
sctp_chunk_free(chunk);
|
||||
} else {
|
||||
if (TSN_lte(tsn, asoc->adv_peer_ack_point+1)) {
|
||||
|
|
Loading…
Reference in a new issue