diff options
-rw-r--r-- | include/net/sctp/structs.h | 4 | ||||
-rw-r--r-- | net/sctp/associola.c | 1 | ||||
-rw-r--r-- | net/sctp/output.c | 23 | ||||
-rw-r--r-- | net/sctp/outqueue.c | 15 | ||||
-rw-r--r-- | net/sctp/transport.c | 38 |
5 files changed, 58 insertions, 23 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index ac794a6823eb..bc3f8d879c5c 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -942,6 +942,8 @@ struct sctp_transport { | |||
942 | /* Data that has been sent, but not acknowledged. */ | 942 | /* Data that has been sent, but not acknowledged. */ |
943 | __u32 flight_size; | 943 | __u32 flight_size; |
944 | 944 | ||
945 | __u32 burst_limited; /* Holds old cwnd when max.burst is applied */ | ||
946 | |||
945 | /* TSN marking the fast recovery exit point */ | 947 | /* TSN marking the fast recovery exit point */ |
946 | __u32 fast_recovery_exit; | 948 | __u32 fast_recovery_exit; |
947 | 949 | ||
@@ -1070,6 +1072,8 @@ void sctp_transport_put(struct sctp_transport *); | |||
1070 | void sctp_transport_update_rto(struct sctp_transport *, __u32); | 1072 | void sctp_transport_update_rto(struct sctp_transport *, __u32); |
1071 | void sctp_transport_raise_cwnd(struct sctp_transport *, __u32, __u32); | 1073 | void sctp_transport_raise_cwnd(struct sctp_transport *, __u32, __u32); |
1072 | void sctp_transport_lower_cwnd(struct sctp_transport *, sctp_lower_cwnd_t); | 1074 | void sctp_transport_lower_cwnd(struct sctp_transport *, sctp_lower_cwnd_t); |
1075 | void sctp_transport_burst_limited(struct sctp_transport *); | ||
1076 | void sctp_transport_burst_reset(struct sctp_transport *); | ||
1073 | unsigned long sctp_transport_timeout(struct sctp_transport *); | 1077 | unsigned long sctp_transport_timeout(struct sctp_transport *); |
1074 | void sctp_transport_reset(struct sctp_transport *); | 1078 | void sctp_transport_reset(struct sctp_transport *); |
1075 | void sctp_transport_update_pmtu(struct sctp_transport *, u32); | 1079 | void sctp_transport_update_pmtu(struct sctp_transport *, u32); |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 37e982510bea..880dae2ca87b 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -738,6 +738,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
738 | 738 | ||
739 | peer->partial_bytes_acked = 0; | 739 | peer->partial_bytes_acked = 0; |
740 | peer->flight_size = 0; | 740 | peer->flight_size = 0; |
741 | peer->burst_limited = 0; | ||
741 | 742 | ||
742 | /* Set the transport's RTO.initial value */ | 743 | /* Set the transport's RTO.initial value */ |
743 | peer->rto = asoc->rto_initial; | 744 | peer->rto = asoc->rto_initial; |
diff --git a/net/sctp/output.c b/net/sctp/output.c index 9e8e0ea844be..b210d2077e28 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
@@ -615,7 +615,6 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, | |||
615 | sctp_xmit_t retval = SCTP_XMIT_OK; | 615 | sctp_xmit_t retval = SCTP_XMIT_OK; |
616 | size_t datasize, rwnd, inflight, flight_size; | 616 | size_t datasize, rwnd, inflight, flight_size; |
617 | struct sctp_transport *transport = packet->transport; | 617 | struct sctp_transport *transport = packet->transport; |
618 | __u32 max_burst_bytes; | ||
619 | struct sctp_association *asoc = transport->asoc; | 618 | struct sctp_association *asoc = transport->asoc; |
620 | struct sctp_outq *q = &asoc->outqueue; | 619 | struct sctp_outq *q = &asoc->outqueue; |
621 | 620 | ||
@@ -648,28 +647,6 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, | |||
648 | } | 647 | } |
649 | } | 648 | } |
650 | 649 | ||
651 | /* sctpimpguide-05 2.14.2 | ||
652 | * D) When the time comes for the sender to | ||
653 | * transmit new DATA chunks, the protocol parameter Max.Burst MUST | ||
654 | * first be applied to limit how many new DATA chunks may be sent. | ||
655 | * The limit is applied by adjusting cwnd as follows: | ||
656 | * if ((flightsize + Max.Burst * MTU) < cwnd) | ||
657 | * cwnd = flightsize + Max.Burst * MTU | ||
658 | */ | ||
659 | max_burst_bytes = asoc->max_burst * asoc->pathmtu; | ||
660 | if ((flight_size + max_burst_bytes) < transport->cwnd) { | ||
661 | transport->cwnd = flight_size + max_burst_bytes; | ||
662 | SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " | ||
663 | "transport: %p, cwnd: %d, " | ||
664 | "ssthresh: %d, flight_size: %d, " | ||
665 | "pba: %d\n", | ||
666 | __func__, transport, | ||
667 | transport->cwnd, | ||
668 | transport->ssthresh, | ||
669 | transport->flight_size, | ||
670 | transport->partial_bytes_acked); | ||
671 | } | ||
672 | |||
673 | /* RFC 2960 6.1 Transmission of DATA Chunks | 650 | /* RFC 2960 6.1 Transmission of DATA Chunks |
674 | * | 651 | * |
675 | * B) At any given time, the sender MUST NOT transmit new data | 652 | * B) At any given time, the sender MUST NOT transmit new data |
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 5732661c87d3..2f2377369e2b 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -931,6 +931,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
931 | goto sctp_flush_out; | 931 | goto sctp_flush_out; |
932 | } | 932 | } |
933 | 933 | ||
934 | /* Apply Max.Burst limitation to the current transport in | ||
935 | * case it will be used for new data. We are going to | ||
936 | * rest it before we return, but we want to apply the limit | ||
937 | * to the currently queued data. | ||
938 | */ | ||
939 | if (transport) | ||
940 | sctp_transport_burst_limited(transport); | ||
941 | |||
934 | /* Finally, transmit new packets. */ | 942 | /* Finally, transmit new packets. */ |
935 | while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { | 943 | while ((chunk = sctp_outq_dequeue_data(q)) != NULL) { |
936 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid | 944 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid |
@@ -976,6 +984,10 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
976 | packet = &transport->packet; | 984 | packet = &transport->packet; |
977 | sctp_packet_config(packet, vtag, | 985 | sctp_packet_config(packet, vtag, |
978 | asoc->peer.ecn_capable); | 986 | asoc->peer.ecn_capable); |
987 | /* We've switched transports, so apply the | ||
988 | * Burst limit to the new transport. | ||
989 | */ | ||
990 | sctp_transport_burst_limited(transport); | ||
979 | } | 991 | } |
980 | 992 | ||
981 | SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ", | 993 | SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ", |
@@ -1070,6 +1082,9 @@ sctp_flush_out: | |||
1070 | packet = &t->packet; | 1082 | packet = &t->packet; |
1071 | if (!sctp_packet_empty(packet)) | 1083 | if (!sctp_packet_empty(packet)) |
1072 | error = sctp_packet_transmit(packet); | 1084 | error = sctp_packet_transmit(packet); |
1085 | |||
1086 | /* Clear the burst limited state, if any */ | ||
1087 | sctp_transport_burst_reset(t); | ||
1073 | } | 1088 | } |
1074 | 1089 | ||
1075 | return error; | 1090 | return error; |
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 2df29cbdaf5a..9a6cb22d129f 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
@@ -576,6 +576,43 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, | |||
576 | transport->cwnd, transport->ssthresh); | 576 | transport->cwnd, transport->ssthresh); |
577 | } | 577 | } |
578 | 578 | ||
579 | /* Apply Max.Burst limit to the congestion window: | ||
580 | * sctpimpguide-05 2.14.2 | ||
581 | * D) When the time comes for the sender to | ||
582 | * transmit new DATA chunks, the protocol parameter Max.Burst MUST | ||
583 | * first be applied to limit how many new DATA chunks may be sent. | ||
584 | * The limit is applied by adjusting cwnd as follows: | ||
585 | * if ((flightsize+ Max.Burst * MTU) < cwnd) | ||
586 | * cwnd = flightsize + Max.Burst * MTU | ||
587 | */ | ||
588 | |||
589 | void sctp_transport_burst_limited(struct sctp_transport *t) | ||
590 | { | ||
591 | struct sctp_association *asoc = t->asoc; | ||
592 | u32 old_cwnd = t->cwnd; | ||
593 | u32 max_burst_bytes; | ||
594 | |||
595 | if (t->burst_limited) | ||
596 | return; | ||
597 | |||
598 | max_burst_bytes = t->flight_size + (asoc->max_burst * asoc->pathmtu); | ||
599 | if (max_burst_bytes < old_cwnd) { | ||
600 | t->cwnd = max_burst_bytes; | ||
601 | t->burst_limited = old_cwnd; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | /* Restore the old cwnd congestion window, after the burst had it's | ||
606 | * desired effect. | ||
607 | */ | ||
608 | void sctp_transport_burst_reset(struct sctp_transport *t) | ||
609 | { | ||
610 | if (t->burst_limited) { | ||
611 | t->cwnd = t->burst_limited; | ||
612 | t->burst_limited = 0; | ||
613 | } | ||
614 | } | ||
615 | |||
579 | /* What is the next timeout value for this transport? */ | 616 | /* What is the next timeout value for this transport? */ |
580 | unsigned long sctp_transport_timeout(struct sctp_transport *t) | 617 | unsigned long sctp_transport_timeout(struct sctp_transport *t) |
581 | { | 618 | { |
@@ -598,6 +635,7 @@ void sctp_transport_reset(struct sctp_transport *t) | |||
598 | * (see Section 6.2.1) | 635 | * (see Section 6.2.1) |
599 | */ | 636 | */ |
600 | t->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380)); | 637 | t->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380)); |
638 | t->burst_limited = 0; | ||
601 | t->ssthresh = asoc->peer.i.a_rwnd; | 639 | t->ssthresh = asoc->peer.i.a_rwnd; |
602 | t->last_rto = t->rto = asoc->rto_initial; | 640 | t->last_rto = t->rto = asoc->rto_initial; |
603 | t->rtt = 0; | 641 | t->rtt = 0; |