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

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

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: 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 a6465234
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -1051,7 +1051,7 @@ void sctp_transport_route(struct sctp_transport *, union sctp_addr *,
			  struct sctp_sock *);
void sctp_transport_pmtu(struct sctp_transport *);
void sctp_transport_free(struct sctp_transport *);
void sctp_transport_reset_timers(struct sctp_transport *);
void sctp_transport_reset_timers(struct sctp_transport *, int);
void sctp_transport_hold(struct sctp_transport *);
void sctp_transport_put(struct sctp_transport *);
void sctp_transport_update_rto(struct sctp_transport *, __u32);
@@ -1141,6 +1141,9 @@ struct sctp_outq {
	/* How many unackd bytes do we have in-flight?	*/
	__u32 outstanding_bytes;

	/* Are we doing fast-rtx on this queue */
	char fast_rtx;

	/* Corked? */
	char cork;

+31 −11
Original line number Diff line number Diff line
@@ -208,6 +208,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
	INIT_LIST_HEAD(&q->sacked);
	INIT_LIST_HEAD(&q->abandoned);

	q->fast_rtx = 0;
	q->outstanding_bytes = 0;
	q->empty = 1;
	q->cork  = 0;
@@ -500,6 +501,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
	case SCTP_RTXR_FAST_RTX:
		SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
		sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
		q->fast_rtx = 1;
		break;
	case SCTP_RTXR_PMTUD:
		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,
	sctp_xmit_t status;
	struct sctp_chunk *chunk, *chunk1;
	struct sctp_association *asoc;
	int fast_rtx;
	int error = 0;
	int timer = 0;

	asoc = q->asoc;
	lqueue = &q->retransmit;
	fast_rtx = q->fast_rtx;

	/* RFC 2960 6.3.3 Handle T3-rtx Expiration
	 *
@@ -587,13 +592,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
		switch (status) {
		case SCTP_XMIT_PMTU_FULL:
			/* Send this packet.  */
			if ((error = sctp_packet_transmit(pkt)) == 0)
				*start_timer = 1;
			error = sctp_packet_transmit(pkt);

			/* If we are retransmitting, we should only
			 * send a single packet.
			 */
			if (rtx_timeout) {
			if (rtx_timeout || fast_rtx) {
				list_add(lchunk, lqueue);
				lchunk = NULL;
			}
@@ -603,8 +607,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,

		case SCTP_XMIT_RWND_FULL:
			/* Send this packet. */
			if ((error = sctp_packet_transmit(pkt)) == 0)
				*start_timer = 1;
			error = sctp_packet_transmit(pkt);

			/* Stop sending DATA as there is no more room
			 * at the receiver.
@@ -615,8 +618,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,

		case SCTP_XMIT_NAGLE_DELAY:
			/* Send this packet. */
			if ((error = sctp_packet_transmit(pkt)) == 0)
				*start_timer = 1;
			error = sctp_packet_transmit(pkt);

			/* Stop sending DATA because of nagle delay. */
			list_add(lchunk, lqueue);
@@ -635,7 +637,14 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
			if (chunk->fast_retransmit > 0)
				chunk->fast_retransmit = -1;

			*start_timer = 1;
			/* Force start T3-rtx timer when fast retransmitting
			 * the earliest outstanding TSN
			 */
			if (!timer && fast_rtx &&
			    ntohl(chunk->subh.data_hdr->tsn) ==
					     asoc->ctsn_ack_point + 1)
				timer = 2;

			q->empty = 0;

			/* Retrieve a new chunk to bundle. */
@@ -643,12 +652,16 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
			break;
		}

		/* Set the timer if there were no errors */
		if (!error && !timer)
			timer = 1;

		/* If we are here due to a retransmit timeout or a fast
		 * retransmit and if there are any chunks left in the retransmit
		 * queue that could not fit in the PMTU sized packet, they need
		 * to be marked as ineligible for a subsequent fast retransmit.
		 */
		if (rtx_timeout && !lchunk) {
		if (rtx_timeout && fast_rtx) {
			list_for_each_entry(chunk1, lqueue, transmitted_list) {
				if (chunk1->fast_retransmit > 0)
					chunk1->fast_retransmit = -1;
@@ -656,6 +669,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
		}
	}

	*start_timer = timer;

	/* Clear fast retransmit hint */
	if (fast_rtx)
		q->fast_rtx = 0;

	return error;
}

@@ -862,7 +881,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
						    rtx_timeout, &start_timer);

			if (start_timer)
				sctp_transport_reset_timers(transport);
				sctp_transport_reset_timers(transport,
							    start_timer-1);

			/* This can happen on COOKIE-ECHO resend.  Only
			 * one chunk can get bundled with a COOKIE-ECHO.
@@ -977,7 +997,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
			list_add_tail(&chunk->transmitted_list,
				      &transport->transmitted);

			sctp_transport_reset_timers(transport);
			sctp_transport_reset_timers(transport, start_timer-1);

			q->empty = 0;

+2 −2
Original line number Diff line number Diff line
@@ -191,7 +191,7 @@ static void sctp_transport_destroy(struct sctp_transport *transport)
/* Start T3_rtx timer if it is not already running and update the heartbeat
 * timer.  This routine is called every time a DATA chunk is sent.
 */
void sctp_transport_reset_timers(struct sctp_transport *transport)
void sctp_transport_reset_timers(struct sctp_transport *transport, int force)
{
	/* RFC 2960 6.3.2 Retransmission Timer Rules
	 *
@@ -201,7 +201,7 @@ void sctp_transport_reset_timers(struct sctp_transport *transport)
	 * address.
	 */

	if (!timer_pending(&transport->T3_rtx_timer))
	if (force || !timer_pending(&transport->T3_rtx_timer))
		if (!mod_timer(&transport->T3_rtx_timer,
			       jiffies + transport->rto))
			sctp_transport_hold(transport);