Skip to content

Commit

Permalink
sctp: Start T3-RTX timer when fast retransmitting lowest TSN
Browse files Browse the repository at this point in the history
When we are trying to fast retransmit the lowest outstanding TSN, we
need to restart the T3-RTX timer, so that subsequent timeouts will
correctly tag all the packets necessary for retransmissions.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Tested-by: Wei Yongjun <yjwei@cn.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vlad Yasevich authored and David S. Miller committed Jun 4, 2008
1 parent a646523 commit 62aeaff
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 14 deletions.
5 changes: 4 additions & 1 deletion include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,7 @@ void sctp_transport_route(struct sctp_transport *, union sctp_addr *,
struct sctp_sock *);
void sctp_transport_pmtu(struct sctp_transport *);
void sctp_transport_free(struct sctp_transport *);
void sctp_transport_reset_timers(struct sctp_transport *);
void sctp_transport_reset_timers(struct sctp_transport *, int);
void sctp_transport_hold(struct sctp_transport *);
void sctp_transport_put(struct sctp_transport *);
void sctp_transport_update_rto(struct sctp_transport *, __u32);
Expand Down Expand Up @@ -1141,6 +1141,9 @@ struct sctp_outq {
/* How many unackd bytes do we have in-flight? */
__u32 outstanding_bytes;

/* Are we doing fast-rtx on this queue */
char fast_rtx;

/* Corked? */
char cork;

Expand Down
42 changes: 31 additions & 11 deletions net/sctp/outqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
INIT_LIST_HEAD(&q->sacked);
INIT_LIST_HEAD(&q->abandoned);

q->fast_rtx = 0;
q->outstanding_bytes = 0;
q->empty = 1;
q->cork = 0;
Expand Down Expand Up @@ -500,6 +501,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
case SCTP_RTXR_FAST_RTX:
SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
q->fast_rtx = 1;
break;
case SCTP_RTXR_PMTUD:
SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS);
Expand Down Expand Up @@ -543,10 +545,13 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
sctp_xmit_t status;
struct sctp_chunk *chunk, *chunk1;
struct sctp_association *asoc;
int fast_rtx;
int error = 0;
int timer = 0;

asoc = q->asoc;
lqueue = &q->retransmit;
fast_rtx = q->fast_rtx;

/* RFC 2960 6.3.3 Handle T3-rtx Expiration
*
Expand Down Expand Up @@ -587,13 +592,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
switch (status) {
case SCTP_XMIT_PMTU_FULL:
/* Send this packet. */
if ((error = sctp_packet_transmit(pkt)) == 0)
*start_timer = 1;
error = sctp_packet_transmit(pkt);

/* If we are retransmitting, we should only
* send a single packet.
*/
if (rtx_timeout) {
if (rtx_timeout || fast_rtx) {
list_add(lchunk, lqueue);
lchunk = NULL;
}
Expand All @@ -603,8 +607,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,

case SCTP_XMIT_RWND_FULL:
/* Send this packet. */
if ((error = sctp_packet_transmit(pkt)) == 0)
*start_timer = 1;
error = sctp_packet_transmit(pkt);

/* Stop sending DATA as there is no more room
* at the receiver.
Expand All @@ -615,8 +618,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,

case SCTP_XMIT_NAGLE_DELAY:
/* Send this packet. */
if ((error = sctp_packet_transmit(pkt)) == 0)
*start_timer = 1;
error = sctp_packet_transmit(pkt);

/* Stop sending DATA because of nagle delay. */
list_add(lchunk, lqueue);
Expand All @@ -635,27 +637,44 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
if (chunk->fast_retransmit > 0)
chunk->fast_retransmit = -1;

*start_timer = 1;
/* Force start T3-rtx timer when fast retransmitting
* the earliest outstanding TSN
*/
if (!timer && fast_rtx &&
ntohl(chunk->subh.data_hdr->tsn) ==
asoc->ctsn_ack_point + 1)
timer = 2;

q->empty = 0;

/* Retrieve a new chunk to bundle. */
lchunk = sctp_list_dequeue(lqueue);
break;
}

/* Set the timer if there were no errors */
if (!error && !timer)
timer = 1;

/* If we are here due to a retransmit timeout or a fast
* retransmit and if there are any chunks left in the retransmit
* queue that could not fit in the PMTU sized packet, they need
* to be marked as ineligible for a subsequent fast retransmit.
*/
if (rtx_timeout && !lchunk) {
if (rtx_timeout && fast_rtx) {
list_for_each_entry(chunk1, lqueue, transmitted_list) {
if (chunk1->fast_retransmit > 0)
chunk1->fast_retransmit = -1;
}
}
}

*start_timer = timer;

/* Clear fast retransmit hint */
if (fast_rtx)
q->fast_rtx = 0;

return error;
}

Expand Down Expand Up @@ -862,7 +881,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
rtx_timeout, &start_timer);

if (start_timer)
sctp_transport_reset_timers(transport);
sctp_transport_reset_timers(transport,
start_timer-1);

/* This can happen on COOKIE-ECHO resend. Only
* one chunk can get bundled with a COOKIE-ECHO.
Expand Down Expand Up @@ -977,7 +997,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
list_add_tail(&chunk->transmitted_list,
&transport->transmitted);

sctp_transport_reset_timers(transport);
sctp_transport_reset_timers(transport, start_timer-1);

q->empty = 0;

Expand Down
4 changes: 2 additions & 2 deletions net/sctp/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ static void sctp_transport_destroy(struct sctp_transport *transport)
/* Start T3_rtx timer if it is not already running and update the heartbeat
* timer. This routine is called every time a DATA chunk is sent.
*/
void sctp_transport_reset_timers(struct sctp_transport *transport)
void sctp_transport_reset_timers(struct sctp_transport *transport, int force)
{
/* RFC 2960 6.3.2 Retransmission Timer Rules
*
Expand All @@ -201,7 +201,7 @@ void sctp_transport_reset_timers(struct sctp_transport *transport)
* address.
*/

if (!timer_pending(&transport->T3_rtx_timer))
if (force || !timer_pending(&transport->T3_rtx_timer))
if (!mod_timer(&transport->T3_rtx_timer,
jiffies + transport->rto))
sctp_transport_hold(transport);
Expand Down

0 comments on commit 62aeaff

Please sign in to comment.