diff options
author | Vlad Yasevich <vladislav.yasevich@hp.com> | 2008-06-04 15:39:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-06-04 15:39:11 -0400 |
commit | 62aeaff5ccd96462b7077046357a6d7886175a57 (patch) | |
tree | 8ea18997997a8724222c86f659b559e12bcf4a86 | |
parent | a6465234814efda9ed1dccdba852953f7508e827 (diff) |
sctp: Start T3-RTX timer when fast retransmitting lowest TSN
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>
-rw-r--r-- | include/net/sctp/structs.h | 5 | ||||
-rw-r--r-- | net/sctp/outqueue.c | 42 | ||||
-rw-r--r-- | net/sctp/transport.c | 4 |
3 files changed, 37 insertions, 14 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 67592072a32e..714dc43c0345 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -1051,7 +1051,7 @@ void sctp_transport_route(struct sctp_transport *, union sctp_addr *, | |||
1051 | struct sctp_sock *); | 1051 | struct sctp_sock *); |
1052 | void sctp_transport_pmtu(struct sctp_transport *); | 1052 | void sctp_transport_pmtu(struct sctp_transport *); |
1053 | void sctp_transport_free(struct sctp_transport *); | 1053 | void sctp_transport_free(struct sctp_transport *); |
1054 | void sctp_transport_reset_timers(struct sctp_transport *); | 1054 | void sctp_transport_reset_timers(struct sctp_transport *, int); |
1055 | void sctp_transport_hold(struct sctp_transport *); | 1055 | void sctp_transport_hold(struct sctp_transport *); |
1056 | void sctp_transport_put(struct sctp_transport *); | 1056 | void sctp_transport_put(struct sctp_transport *); |
1057 | void sctp_transport_update_rto(struct sctp_transport *, __u32); | 1057 | void sctp_transport_update_rto(struct sctp_transport *, __u32); |
@@ -1141,6 +1141,9 @@ struct sctp_outq { | |||
1141 | /* How many unackd bytes do we have in-flight? */ | 1141 | /* How many unackd bytes do we have in-flight? */ |
1142 | __u32 outstanding_bytes; | 1142 | __u32 outstanding_bytes; |
1143 | 1143 | ||
1144 | /* Are we doing fast-rtx on this queue */ | ||
1145 | char fast_rtx; | ||
1146 | |||
1144 | /* Corked? */ | 1147 | /* Corked? */ |
1145 | char cork; | 1148 | char cork; |
1146 | 1149 | ||
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 59edfd25a19c..5d3c441e84d3 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -208,6 +208,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) | |||
208 | INIT_LIST_HEAD(&q->sacked); | 208 | INIT_LIST_HEAD(&q->sacked); |
209 | INIT_LIST_HEAD(&q->abandoned); | 209 | INIT_LIST_HEAD(&q->abandoned); |
210 | 210 | ||
211 | q->fast_rtx = 0; | ||
211 | q->outstanding_bytes = 0; | 212 | q->outstanding_bytes = 0; |
212 | q->empty = 1; | 213 | q->empty = 1; |
213 | q->cork = 0; | 214 | q->cork = 0; |
@@ -500,6 +501,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, | |||
500 | case SCTP_RTXR_FAST_RTX: | 501 | case SCTP_RTXR_FAST_RTX: |
501 | SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS); | 502 | SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS); |
502 | sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX); | 503 | sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX); |
504 | q->fast_rtx = 1; | ||
503 | break; | 505 | break; |
504 | case SCTP_RTXR_PMTUD: | 506 | case SCTP_RTXR_PMTUD: |
505 | SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS); | 507 | SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS); |
@@ -543,10 +545,13 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, | |||
543 | sctp_xmit_t status; | 545 | sctp_xmit_t status; |
544 | struct sctp_chunk *chunk, *chunk1; | 546 | struct sctp_chunk *chunk, *chunk1; |
545 | struct sctp_association *asoc; | 547 | struct sctp_association *asoc; |
548 | int fast_rtx; | ||
546 | int error = 0; | 549 | int error = 0; |
550 | int timer = 0; | ||
547 | 551 | ||
548 | asoc = q->asoc; | 552 | asoc = q->asoc; |
549 | lqueue = &q->retransmit; | 553 | lqueue = &q->retransmit; |
554 | fast_rtx = q->fast_rtx; | ||
550 | 555 | ||
551 | /* RFC 2960 6.3.3 Handle T3-rtx Expiration | 556 | /* RFC 2960 6.3.3 Handle T3-rtx Expiration |
552 | * | 557 | * |
@@ -587,13 +592,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, | |||
587 | switch (status) { | 592 | switch (status) { |
588 | case SCTP_XMIT_PMTU_FULL: | 593 | case SCTP_XMIT_PMTU_FULL: |
589 | /* Send this packet. */ | 594 | /* Send this packet. */ |
590 | if ((error = sctp_packet_transmit(pkt)) == 0) | 595 | error = sctp_packet_transmit(pkt); |
591 | *start_timer = 1; | ||
592 | 596 | ||
593 | /* If we are retransmitting, we should only | 597 | /* If we are retransmitting, we should only |
594 | * send a single packet. | 598 | * send a single packet. |
595 | */ | 599 | */ |
596 | if (rtx_timeout) { | 600 | if (rtx_timeout || fast_rtx) { |
597 | list_add(lchunk, lqueue); | 601 | list_add(lchunk, lqueue); |
598 | lchunk = NULL; | 602 | lchunk = NULL; |
599 | } | 603 | } |
@@ -603,8 +607,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, | |||
603 | 607 | ||
604 | case SCTP_XMIT_RWND_FULL: | 608 | case SCTP_XMIT_RWND_FULL: |
605 | /* Send this packet. */ | 609 | /* Send this packet. */ |
606 | if ((error = sctp_packet_transmit(pkt)) == 0) | 610 | error = sctp_packet_transmit(pkt); |
607 | *start_timer = 1; | ||
608 | 611 | ||
609 | /* Stop sending DATA as there is no more room | 612 | /* Stop sending DATA as there is no more room |
610 | * at the receiver. | 613 | * at the receiver. |
@@ -615,8 +618,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, | |||
615 | 618 | ||
616 | case SCTP_XMIT_NAGLE_DELAY: | 619 | case SCTP_XMIT_NAGLE_DELAY: |
617 | /* Send this packet. */ | 620 | /* Send this packet. */ |
618 | if ((error = sctp_packet_transmit(pkt)) == 0) | 621 | error = sctp_packet_transmit(pkt); |
619 | *start_timer = 1; | ||
620 | 622 | ||
621 | /* Stop sending DATA because of nagle delay. */ | 623 | /* Stop sending DATA because of nagle delay. */ |
622 | list_add(lchunk, lqueue); | 624 | list_add(lchunk, lqueue); |
@@ -635,7 +637,14 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, | |||
635 | if (chunk->fast_retransmit > 0) | 637 | if (chunk->fast_retransmit > 0) |
636 | chunk->fast_retransmit = -1; | 638 | chunk->fast_retransmit = -1; |
637 | 639 | ||
638 | *start_timer = 1; | 640 | /* Force start T3-rtx timer when fast retransmitting |
641 | * the earliest outstanding TSN | ||
642 | */ | ||
643 | if (!timer && fast_rtx && | ||
644 | ntohl(chunk->subh.data_hdr->tsn) == | ||
645 | asoc->ctsn_ack_point + 1) | ||
646 | timer = 2; | ||
647 | |||
639 | q->empty = 0; | 648 | q->empty = 0; |
640 | 649 | ||
641 | /* Retrieve a new chunk to bundle. */ | 650 | /* Retrieve a new chunk to bundle. */ |
@@ -643,12 +652,16 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, | |||
643 | break; | 652 | break; |
644 | } | 653 | } |
645 | 654 | ||
655 | /* Set the timer if there were no errors */ | ||
656 | if (!error && !timer) | ||
657 | timer = 1; | ||
658 | |||
646 | /* If we are here due to a retransmit timeout or a fast | 659 | /* If we are here due to a retransmit timeout or a fast |
647 | * retransmit and if there are any chunks left in the retransmit | 660 | * retransmit and if there are any chunks left in the retransmit |
648 | * queue that could not fit in the PMTU sized packet, they need | 661 | * queue that could not fit in the PMTU sized packet, they need |
649 | * to be marked as ineligible for a subsequent fast retransmit. | 662 | * to be marked as ineligible for a subsequent fast retransmit. |
650 | */ | 663 | */ |
651 | if (rtx_timeout && !lchunk) { | 664 | if (rtx_timeout && fast_rtx) { |
652 | list_for_each_entry(chunk1, lqueue, transmitted_list) { | 665 | list_for_each_entry(chunk1, lqueue, transmitted_list) { |
653 | if (chunk1->fast_retransmit > 0) | 666 | if (chunk1->fast_retransmit > 0) |
654 | chunk1->fast_retransmit = -1; | 667 | chunk1->fast_retransmit = -1; |
@@ -656,6 +669,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, | |||
656 | } | 669 | } |
657 | } | 670 | } |
658 | 671 | ||
672 | *start_timer = timer; | ||
673 | |||
674 | /* Clear fast retransmit hint */ | ||
675 | if (fast_rtx) | ||
676 | q->fast_rtx = 0; | ||
677 | |||
659 | return error; | 678 | return error; |
660 | } | 679 | } |
661 | 680 | ||
@@ -862,7 +881,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
862 | rtx_timeout, &start_timer); | 881 | rtx_timeout, &start_timer); |
863 | 882 | ||
864 | if (start_timer) | 883 | if (start_timer) |
865 | sctp_transport_reset_timers(transport); | 884 | sctp_transport_reset_timers(transport, |
885 | start_timer-1); | ||
866 | 886 | ||
867 | /* This can happen on COOKIE-ECHO resend. Only | 887 | /* This can happen on COOKIE-ECHO resend. Only |
868 | * one chunk can get bundled with a COOKIE-ECHO. | 888 | * one chunk can get bundled with a COOKIE-ECHO. |
@@ -977,7 +997,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
977 | list_add_tail(&chunk->transmitted_list, | 997 | list_add_tail(&chunk->transmitted_list, |
978 | &transport->transmitted); | 998 | &transport->transmitted); |
979 | 999 | ||
980 | sctp_transport_reset_timers(transport); | 1000 | sctp_transport_reset_timers(transport, start_timer-1); |
981 | 1001 | ||
982 | q->empty = 0; | 1002 | q->empty = 0; |
983 | 1003 | ||
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 9647fb277221..3f34f61221ec 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
@@ -191,7 +191,7 @@ static void sctp_transport_destroy(struct sctp_transport *transport) | |||
191 | /* Start T3_rtx timer if it is not already running and update the heartbeat | 191 | /* Start T3_rtx timer if it is not already running and update the heartbeat |
192 | * timer. This routine is called every time a DATA chunk is sent. | 192 | * timer. This routine is called every time a DATA chunk is sent. |
193 | */ | 193 | */ |
194 | void sctp_transport_reset_timers(struct sctp_transport *transport) | 194 | void sctp_transport_reset_timers(struct sctp_transport *transport, int force) |
195 | { | 195 | { |
196 | /* RFC 2960 6.3.2 Retransmission Timer Rules | 196 | /* RFC 2960 6.3.2 Retransmission Timer Rules |
197 | * | 197 | * |
@@ -201,7 +201,7 @@ void sctp_transport_reset_timers(struct sctp_transport *transport) | |||
201 | * address. | 201 | * address. |
202 | */ | 202 | */ |
203 | 203 | ||
204 | if (!timer_pending(&transport->T3_rtx_timer)) | 204 | if (force || !timer_pending(&transport->T3_rtx_timer)) |
205 | if (!mod_timer(&transport->T3_rtx_timer, | 205 | if (!mod_timer(&transport->T3_rtx_timer, |
206 | jiffies + transport->rto)) | 206 | jiffies + transport->rto)) |
207 | sctp_transport_hold(transport); | 207 | sctp_transport_hold(transport); |