Skip to content

Commit

Permalink
SCTP: Fix difference cases of retransmit.
Browse files Browse the repository at this point in the history
Commit d0ce929 broke several retransmit
cases including fast retransmit.  The reason is that we should
only delay by rto while doing retranmists as a result of a timeout.
Retransmit as a result of path mtu discover, fast retransmit, or
other evernts that should trigger immidiate retransmissions got broken.

Also, since rto is doubled prior to marking of packets elegable for
retransmission, we never marked correct chunks anyway.

The fix is provide a reason for a given retransmission so that we
can mark chunks appropriately and to save the old rto value to do
comparisons against.

All regressions tests passed with this code.

Spotted by Wei Yongjun <yjwei@cn.fujitsu.com>

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
  • Loading branch information
Vlad Yasevich committed Nov 7, 2007
1 parent f3830cc commit b6157d8
Show file tree
Hide file tree
Showing 8 changed files with 36 additions and 22 deletions.
1 change: 1 addition & 0 deletions include/net/sctp/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ typedef enum {
SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */
SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */
SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */
SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */
SCTP_CMD_LAST
} sctp_verb_t;

Expand Down
1 change: 1 addition & 0 deletions include/net/sctp/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ typedef enum {
SCTP_RTXR_T3_RTX,
SCTP_RTXR_FAST_RTX,
SCTP_RTXR_PMTUD,
SCTP_RTXR_T1_RTX,
} sctp_retransmit_reason_t;

/* Reasons to lower cwnd. */
Expand Down
1 change: 1 addition & 0 deletions include/net/sctp/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ enum
SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS,
SCTP_MIB_DELAY_SACK_EXPIREDS,
SCTP_MIB_AUTOCLOSE_EXPIREDS,
SCTP_MIB_T1_RETRANSMITS,
SCTP_MIB_T3_RETRANSMITS,
SCTP_MIB_PMTUD_RETRANSMITS,
SCTP_MIB_FAST_RETRANSMITS,
Expand Down
5 changes: 3 additions & 2 deletions include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -873,10 +873,11 @@ struct sctp_transport {
* address list derived from the INIT or INIT ACK chunk, a
* number of data elements needs to be maintained including:
*/
__u32 rtt; /* This is the most recent RTT. */

/* RTO : The current retransmission timeout value. */
unsigned long rto;
unsigned long last_rto;

__u32 rtt; /* This is the most recent RTT. */

/* RTTVAR : The current RTT variation. */
__u32 rttvar;
Expand Down
33 changes: 17 additions & 16 deletions net/sctp/outqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ static void sctp_insert_list(struct list_head *head, struct list_head *new)
/* Mark all the eligible packets on a transport for retransmission. */
void sctp_retransmit_mark(struct sctp_outq *q,
struct sctp_transport *transport,
__u8 fast_retransmit)
__u8 reason)
{
struct list_head *lchunk, *ltemp;
struct sctp_chunk *chunk;
Expand Down Expand Up @@ -412,20 +412,20 @@ void sctp_retransmit_mark(struct sctp_outq *q,
continue;
}

/* If we are doing retransmission due to a fast retransmit,
* only the chunk's that are marked for fast retransmit
* should be added to the retransmit queue. If we are doing
* retransmission due to a timeout or pmtu discovery, only the
* chunks that are not yet acked should be added to the
* retransmit queue.
/* If we are doing retransmission due to a timeout or pmtu
* discovery, only the chunks that are not yet acked should
* be added to the retransmit queue.
*/
if ((fast_retransmit && (chunk->fast_retransmit > 0)) ||
(!fast_retransmit && !chunk->tsn_gap_acked)) {
if ((reason == SCTP_RTXR_FAST_RTX &&
(chunk->fast_retransmit > 0)) ||
(reason != SCTP_RTXR_FAST_RTX && !chunk->tsn_gap_acked)) {
/* If this chunk was sent less then 1 rto ago, do not
* retransmit this chunk, but give the peer time
* to acknowlege it.
* to acknowlege it. Do this only when
* retransmitting due to T3 timeout.
*/
if ((jiffies - chunk->sent_at) < transport->rto)
if (reason == SCTP_RTXR_T3_RTX &&
(jiffies - chunk->sent_at) < transport->last_rto)
continue;

/* RFC 2960 6.2.1 Processing a Received SACK
Expand Down Expand Up @@ -467,10 +467,10 @@ void sctp_retransmit_mark(struct sctp_outq *q,
}
}

SCTP_DEBUG_PRINTK("%s: transport: %p, fast_retransmit: %d, "
SCTP_DEBUG_PRINTK("%s: transport: %p, reason: %d, "
"cwnd: %d, ssthresh: %d, flight_size: %d, "
"pba: %d\n", __FUNCTION__,
transport, fast_retransmit,
transport, reason,
transport->cwnd, transport->ssthresh,
transport->flight_size,
transport->partial_bytes_acked);
Expand All @@ -484,7 +484,6 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
sctp_retransmit_reason_t reason)
{
int error = 0;
__u8 fast_retransmit = 0;

switch(reason) {
case SCTP_RTXR_T3_RTX:
Expand All @@ -499,16 +498,18 @@ 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);
fast_retransmit = 1;
break;
case SCTP_RTXR_PMTUD:
SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS);
break;
case SCTP_RTXR_T1_RTX:
SCTP_INC_STATS(SCTP_MIB_T1_RETRANSMITS);
break;
default:
BUG();
}

sctp_retransmit_mark(q, transport, fast_retransmit);
sctp_retransmit_mark(q, transport, reason);

/* PR-SCTP A5) Any time the T3-rtx timer expires, on any destination,
* the sender SHOULD try to advance the "Advanced.Peer.Ack.Point" by
Expand Down
10 changes: 9 additions & 1 deletion net/sctp/sm_sideeffect.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
* maximum value discussed in rule C7 above (RTO.max) may be
* used to provide an upper bound to this doubling operation.
*/
transport->last_rto = transport->rto;
transport->rto = min((transport->rto * 2), transport->asoc->rto_max);
}

Expand Down Expand Up @@ -1267,6 +1268,12 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
sctp_ootb_pkt_free(packet);
break;

case SCTP_CMD_T1_RETRAN:
/* Mark a transport for retransmission. */
sctp_retransmit(&asoc->outqueue, cmd->obj.transport,
SCTP_RTXR_T1_RTX);
break;

case SCTP_CMD_RETRAN:
/* Mark a transport for retransmission. */
sctp_retransmit(&asoc->outqueue, cmd->obj.transport,
Expand Down Expand Up @@ -1393,7 +1400,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
list_for_each(pos, &asoc->peer.transport_addr_list) {
t = list_entry(pos, struct sctp_transport,
transports);
sctp_retransmit_mark(&asoc->outqueue, t, 0);
sctp_retransmit_mark(&asoc->outqueue, t,
SCTP_RTXR_T1_RTX);
}

sctp_add_cmd_sf(commands,
Expand Down
2 changes: 1 addition & 1 deletion net/sctp/sm_statefuns.c
Original file line number Diff line number Diff line change
Expand Up @@ -2305,7 +2305,7 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
/* If we've sent any data bundled with COOKIE-ECHO we will need to
* resend
*/
sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN,
sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN,
SCTP_TRANSPORT(asoc->peer.primary_path));

/* Cast away the const modifier, as we want to just
Expand Down
5 changes: 3 additions & 2 deletions net/sctp/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
* given destination transport address, set RTO to the protocol
* parameter 'RTO.Initial'.
*/
peer->last_rto = peer->rto = msecs_to_jiffies(sctp_rto_initial);
peer->rtt = 0;
peer->rto = msecs_to_jiffies(sctp_rto_initial);
peer->rttvar = 0;
peer->srtt = 0;
peer->rto_pending = 0;
Expand Down Expand Up @@ -385,6 +385,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
tp->rto = tp->asoc->rto_max;

tp->rtt = rtt;
tp->last_rto = tp->rto;

/* Reset rto_pending so that a new RTT measurement is started when a
* new data chunk is sent.
Expand Down Expand Up @@ -578,7 +579,7 @@ void sctp_transport_reset(struct sctp_transport *t)
*/
t->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380));
t->ssthresh = asoc->peer.i.a_rwnd;
t->rto = asoc->rto_initial;
t->last_rto = t->rto = asoc->rto_initial;
t->rtt = 0;
t->srtt = 0;
t->rttvar = 0;
Expand Down

0 comments on commit b6157d8

Please sign in to comment.