summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/sctp/structs.h4
-rw-r--r--net/sctp/associola.c1
-rw-r--r--net/sctp/output.c23
-rw-r--r--net/sctp/outqueue.c15
-rw-r--r--net/sctp/transport.c38
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 {
/* Data that has been sent, but not acknowledged. */
__u32 flight_size;
+ __u32 burst_limited; /* Holds old cwnd when max.burst is applied */
+
/* TSN marking the fast recovery exit point */
__u32 fast_recovery_exit;
@@ -1070,6 +1072,8 @@ void sctp_transport_put(struct sctp_transport *);
void sctp_transport_update_rto(struct sctp_transport *, __u32);
void sctp_transport_raise_cwnd(struct sctp_transport *, __u32, __u32);
void sctp_transport_lower_cwnd(struct sctp_transport *, sctp_lower_cwnd_t);
+void sctp_transport_burst_limited(struct sctp_transport *);
+void sctp_transport_burst_reset(struct sctp_transport *);
unsigned long sctp_transport_timeout(struct sctp_transport *);
void sctp_transport_reset(struct sctp_transport *);
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,
peer->partial_bytes_acked = 0;
peer->flight_size = 0;
+ peer->burst_limited = 0;
/* Set the transport's RTO.initial value */
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,
sctp_xmit_t retval = SCTP_XMIT_OK;
size_t datasize, rwnd, inflight, flight_size;
struct sctp_transport *transport = packet->transport;
- __u32 max_burst_bytes;
struct sctp_association *asoc = transport->asoc;
struct sctp_outq *q = &asoc->outqueue;
@@ -648,28 +647,6 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
}
}
- /* sctpimpguide-05 2.14.2
- * D) When the time comes for the sender to
- * transmit new DATA chunks, the protocol parameter Max.Burst MUST
- * first be applied to limit how many new DATA chunks may be sent.
- * The limit is applied by adjusting cwnd as follows:
- * if ((flightsize + Max.Burst * MTU) < cwnd)
- * cwnd = flightsize + Max.Burst * MTU
- */
- max_burst_bytes = asoc->max_burst * asoc->pathmtu;
- if ((flight_size + max_burst_bytes) < transport->cwnd) {
- transport->cwnd = flight_size + max_burst_bytes;
- SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: "
- "transport: %p, cwnd: %d, "
- "ssthresh: %d, flight_size: %d, "
- "pba: %d\n",
- __func__, transport,
- transport->cwnd,
- transport->ssthresh,
- transport->flight_size,
- transport->partial_bytes_acked);
- }
-
/* RFC 2960 6.1 Transmission of DATA Chunks
*
* 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)
goto sctp_flush_out;
}
+ /* Apply Max.Burst limitation to the current transport in
+ * case it will be used for new data. We are going to
+ * rest it before we return, but we want to apply the limit
+ * to the currently queued data.
+ */
+ if (transport)
+ sctp_transport_burst_limited(transport);
+
/* Finally, transmit new packets. */
while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
/* 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)
packet = &transport->packet;
sctp_packet_config(packet, vtag,
asoc->peer.ecn_capable);
+ /* We've switched transports, so apply the
+ * Burst limit to the new transport.
+ */
+ sctp_transport_burst_limited(transport);
}
SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ",
@@ -1070,6 +1082,9 @@ sctp_flush_out:
packet = &t->packet;
if (!sctp_packet_empty(packet))
error = sctp_packet_transmit(packet);
+
+ /* Clear the burst limited state, if any */
+ sctp_transport_burst_reset(t);
}
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,
transport->cwnd, transport->ssthresh);
}
+/* Apply Max.Burst limit to the congestion window:
+ * sctpimpguide-05 2.14.2
+ * D) When the time comes for the sender to
+ * transmit new DATA chunks, the protocol parameter Max.Burst MUST
+ * first be applied to limit how many new DATA chunks may be sent.
+ * The limit is applied by adjusting cwnd as follows:
+ * if ((flightsize+ Max.Burst * MTU) < cwnd)
+ * cwnd = flightsize + Max.Burst * MTU
+ */
+
+void sctp_transport_burst_limited(struct sctp_transport *t)
+{
+ struct sctp_association *asoc = t->asoc;
+ u32 old_cwnd = t->cwnd;
+ u32 max_burst_bytes;
+
+ if (t->burst_limited)
+ return;
+
+ max_burst_bytes = t->flight_size + (asoc->max_burst * asoc->pathmtu);
+ if (max_burst_bytes < old_cwnd) {
+ t->cwnd = max_burst_bytes;
+ t->burst_limited = old_cwnd;
+ }
+}
+
+/* Restore the old cwnd congestion window, after the burst had it's
+ * desired effect.
+ */
+void sctp_transport_burst_reset(struct sctp_transport *t)
+{
+ if (t->burst_limited) {
+ t->cwnd = t->burst_limited;
+ t->burst_limited = 0;
+ }
+}
+
/* What is the next timeout value for this transport? */
unsigned long sctp_transport_timeout(struct sctp_transport *t)
{
@@ -598,6 +635,7 @@ void sctp_transport_reset(struct sctp_transport *t)
* (see Section 6.2.1)
*/
t->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380));
+ t->burst_limited = 0;
t->ssthresh = asoc->peer.i.a_rwnd;
t->last_rto = t->rto = asoc->rto_initial;
t->rtt = 0;