Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6465234 authored by Vlad Yasevich's avatar Vlad Yasevich Committed by David S. Miller
Browse files

sctp: Correctly implement Fast Recovery cwnd manipulations.



Correctly keep track of Fast Recovery state and do not reduce
congestion window multiple times during sucht state.

Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
Tested-by: default avatarWei Yongjun <yjwei@cn.fujitsu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 159c6bea
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -902,7 +902,10 @@ struct sctp_transport {
	 *		calculation completes (i.e. the DATA chunk
	 *		is SACK'd) clear this flag.
	 */
	int rto_pending;
	__u8 rto_pending;

	/* Flag to track the current fast recovery state */
	__u8 fast_recovery;

	/*
	 * These are the congestion stats.
@@ -921,6 +924,9 @@ struct sctp_transport {
	/* Data that has been sent, but not acknowledged. */
	__u32 flight_size;

	/* TSN marking the fast recovery exit point */
	__u32 fast_recovery_exit;

	/* Destination */
	struct dst_entry *dst;
	/* Source address. */
+32 −12
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
	peer->rttvar = 0;
	peer->srtt = 0;
	peer->rto_pending = 0;
	peer->fast_recovery = 0;

	peer->last_time_heard = jiffies;
	peer->last_time_used = jiffies;
@@ -403,11 +404,16 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
	cwnd = transport->cwnd;
	flight_size = transport->flight_size;

	/* See if we need to exit Fast Recovery first */
	if (transport->fast_recovery &&
	    TSN_lte(transport->fast_recovery_exit, sack_ctsn))
		transport->fast_recovery = 0;

	/* The appropriate cwnd increase algorithm is performed if, and only
	 * if the cumulative TSN has advanced and the congestion window is
	 * if the cumulative TSN whould advanced and the congestion window is
	 * being fully utilized.
	 */
	if ((transport->asoc->ctsn_ack_point >= sack_ctsn) ||
	if (TSN_lte(sack_ctsn, transport->asoc->ctsn_ack_point) ||
	    (flight_size < cwnd))
		return;

@@ -416,17 +422,23 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
	pmtu = transport->asoc->pathmtu;

	if (cwnd <= ssthresh) {
		/* RFC 2960 7.2.1, sctpimpguide-05 2.14.2 When cwnd is less
		 * than or equal to ssthresh an SCTP endpoint MUST use the
		 * slow start algorithm to increase cwnd only if the current
		 * congestion window is being fully utilized and an incoming
		 * SACK advances the Cumulative TSN Ack Point. Only when these
		 * two conditions are met can the cwnd be increased otherwise
		 * the cwnd MUST not be increased. If these conditions are met
		 * then cwnd MUST be increased by at most the lesser of
		 * 1) the total size of the previously outstanding DATA
		 * chunk(s) acknowledged, and 2) the destination's path MTU.
		/* RFC 4960 7.2.1
		 * o  When cwnd is less than or equal to ssthresh, an SCTP
		 *    endpoint MUST use the slow-start algorithm to increase
		 *    cwnd only if the current congestion window is being fully
		 *    utilized, an incoming SACK advances the Cumulative TSN
		 *    Ack Point, and the data sender is not in Fast Recovery.
		 *    Only when these three conditions are met can the cwnd be
		 *    increased; otherwise, the cwnd MUST not be increased.
		 *    If these conditions are met, then cwnd MUST be increased
		 *    by, at most, the lesser of 1) the total size of the
		 *    previously outstanding DATA chunk(s) acknowledged, and
		 *    2) the destination's path MTU.  This upper bound protects
		 *    against the ACK-Splitting attack outlined in [SAVAGE99].
		 */
		if (transport->fast_recovery)
			return;

		if (bytes_acked > pmtu)
			cwnd += pmtu;
		else
@@ -502,6 +514,13 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
		 *      cwnd = ssthresh
		 *      partial_bytes_acked = 0
		 */
		if (transport->fast_recovery)
			return;

		/* Mark Fast recovery */
		transport->fast_recovery = 1;
		transport->fast_recovery_exit = transport->asoc->next_tsn - 1;

		transport->ssthresh = max(transport->cwnd/2,
					  4*transport->asoc->pathmtu);
		transport->cwnd = transport->ssthresh;
@@ -586,6 +605,7 @@ void sctp_transport_reset(struct sctp_transport *t)
	t->flight_size = 0;
	t->error_count = 0;
	t->rto_pending = 0;
	t->fast_recovery = 0;

	/* Initialize the state information for SFR-CACC */
	t->cacc.changeover_active = 0;