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); |
