sctp: Update max.burst implementation
Current implementation of max.burst ends up limiting new data during cwnd decay period. The decay is happening becuase the connection is idle and we are allowed to fill the congestion window. The point of max.burst is to limit micro-bursts in response to large acks. This still happens, as max.burst is still applied to each transmit opportunity. It will also apply if a very large send is made (greater then allowed by burst). Tested-by: Florian Niederbacher <florian.niederbacher@student.uibk.ac.at> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
This commit is contained in:
parent
a5b03ad214
commit
46d5a80855
5 changed files with 58 additions and 23 deletions
|
@ -942,6 +942,8 @@ struct sctp_transport {
|
||||||
/* Data that has been sent, but not acknowledged. */
|
/* Data that has been sent, but not acknowledged. */
|
||||||
__u32 flight_size;
|
__u32 flight_size;
|
||||||
|
|
||||||
|
__u32 burst_limited; /* Holds old cwnd when max.burst is applied */
|
||||||
|
|
||||||
/* TSN marking the fast recovery exit point */
|
/* TSN marking the fast recovery exit point */
|
||||||
__u32 fast_recovery_exit;
|
__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_update_rto(struct sctp_transport *, __u32);
|
||||||
void sctp_transport_raise_cwnd(struct sctp_transport *, __u32, __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_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 *);
|
unsigned long sctp_transport_timeout(struct sctp_transport *);
|
||||||
void sctp_transport_reset(struct sctp_transport *);
|
void sctp_transport_reset(struct sctp_transport *);
|
||||||
void sctp_transport_update_pmtu(struct sctp_transport *, u32);
|
void sctp_transport_update_pmtu(struct sctp_transport *, u32);
|
||||||
|
|
|
@ -738,6 +738,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
|
||||||
|
|
||||||
peer->partial_bytes_acked = 0;
|
peer->partial_bytes_acked = 0;
|
||||||
peer->flight_size = 0;
|
peer->flight_size = 0;
|
||||||
|
peer->burst_limited = 0;
|
||||||
|
|
||||||
/* Set the transport's RTO.initial value */
|
/* Set the transport's RTO.initial value */
|
||||||
peer->rto = asoc->rto_initial;
|
peer->rto = asoc->rto_initial;
|
||||||
|
|
|
@ -615,7 +615,6 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
|
||||||
sctp_xmit_t retval = SCTP_XMIT_OK;
|
sctp_xmit_t retval = SCTP_XMIT_OK;
|
||||||
size_t datasize, rwnd, inflight, flight_size;
|
size_t datasize, rwnd, inflight, flight_size;
|
||||||
struct sctp_transport *transport = packet->transport;
|
struct sctp_transport *transport = packet->transport;
|
||||||
__u32 max_burst_bytes;
|
|
||||||
struct sctp_association *asoc = transport->asoc;
|
struct sctp_association *asoc = transport->asoc;
|
||||||
struct sctp_outq *q = &asoc->outqueue;
|
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
|
/* RFC 2960 6.1 Transmission of DATA Chunks
|
||||||
*
|
*
|
||||||
* B) At any given time, the sender MUST NOT transmit new data
|
* B) At any given time, the sender MUST NOT transmit new data
|
||||||
|
|
|
@ -931,6 +931,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
|
||||||
goto sctp_flush_out;
|
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. */
|
/* Finally, transmit new packets. */
|
||||||
while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
|
while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
|
||||||
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
|
/* 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;
|
packet = &transport->packet;
|
||||||
sctp_packet_config(packet, vtag,
|
sctp_packet_config(packet, vtag,
|
||||||
asoc->peer.ecn_capable);
|
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]), ",
|
SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ",
|
||||||
|
@ -1070,6 +1082,9 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
|
||||||
packet = &t->packet;
|
packet = &t->packet;
|
||||||
if (!sctp_packet_empty(packet))
|
if (!sctp_packet_empty(packet))
|
||||||
error = sctp_packet_transmit(packet);
|
error = sctp_packet_transmit(packet);
|
||||||
|
|
||||||
|
/* Clear the burst limited state, if any */
|
||||||
|
sctp_transport_burst_reset(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -576,6 +576,43 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
|
||||||
transport->cwnd, transport->ssthresh);
|
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? */
|
/* What is the next timeout value for this transport? */
|
||||||
unsigned long sctp_transport_timeout(struct sctp_transport *t)
|
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)
|
* (see Section 6.2.1)
|
||||||
*/
|
*/
|
||||||
t->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380));
|
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->ssthresh = asoc->peer.i.a_rwnd;
|
||||||
t->last_rto = t->rto = asoc->rto_initial;
|
t->last_rto = t->rto = asoc->rto_initial;
|
||||||
t->rtt = 0;
|
t->rtt = 0;
|
||||||
|
|
Loading…
Reference in a new issue