tcp_connection_cleanup (tc);
break;
case TCP_STATE_SYN_SENT:
- session_stream_connect_notify (&tc->connection, 1 /* fail */ );
+ session_stream_connect_notify (&tc->connection, SESSION_E_REFUSED);
tcp_connection_cleanup (tc);
break;
case TCP_STATE_ESTABLISHED:
break;
case TCP_STATE_SYN_SENT:
/* Do not program ntf because the connection is half-open */
+ tc->rst_state = tc->state;
tcp_handle_rst (tc);
break;
case TCP_STATE_ESTABLISHED:
/**
* Compute smoothed RTT as per VJ's '88 SIGCOMM and RFC6298
*
- * Note that although the original article, srtt and rttvar are scaled
+ * Note that although in the original article srtt and rttvar are scaled
* to minimize round-off errors, here we don't. Instead, we rely on
* better precision time measurements.
+ *
+ * A known limitation of the algorithm is that a drop in rtt results in a
+ * rttvar increase and bigger RTO.
+ *
+ * mrtt must be provided in @ref TCP_TICK multiples, i.e., in us. Note that
+ * timestamps are measured as ms ticks so they must be converted before
+ * calling this function.
*/
static void
tcp_estimate_rtt (tcp_connection_t * tc, u32 mrtt)
{
int err, diff;
- if (tc->srtt != 0)
- {
- err = mrtt - tc->srtt;
-
- /* XXX Drop in RTT results in RTTVAR increase and bigger RTO.
- * The increase should be bound */
- tc->srtt = clib_max ((int) tc->srtt + (err >> 3), 1);
- diff = (clib_abs (err) - (int) tc->rttvar) >> 2;
- tc->rttvar = clib_max ((int) tc->rttvar + diff, 1);
- }
- else
- {
- /* First measurement. */
- tc->srtt = mrtt;
- tc->rttvar = mrtt >> 1;
- }
+ err = mrtt - tc->srtt;
+ tc->srtt = clib_max ((int) tc->srtt + (err >> 3), 1);
+ diff = (clib_abs (err) - (int) tc->rttvar) >> 2;
+ tc->rttvar = clib_max ((int) tc->rttvar + diff, 1);
}
static inline void
* seq_lt (tc->snd_una, ack). This is a condition for calling update_rtt */
else if (tcp_opts_tstamp (&tc->rcv_opts) && tc->rcv_opts.tsecr)
{
- u32 now = tcp_tstamp (tc);
- mrtt = clib_max (now - tc->rcv_opts.tsecr, 1);
+ mrtt = clib_max (tcp_tstamp (tc) - tc->rcv_opts.tsecr, 1);
+ mrtt *= TCP_TSTP_TO_HZ;
}
estimate_rtt:
}
else
{
- mrtt = tcp_time_now_w_thread (thread_index) - tc->rcv_opts.tsecr;
- mrtt = clib_max (mrtt, 1);
+ mrtt = tcp_tstamp (tc) - tc->rcv_opts.tsecr;
+ mrtt = clib_max (mrtt, 1) * TCP_TSTP_TO_HZ;
/* Due to retransmits we don't know the initial mrtt */
if (tc->rto_boff && mrtt > 1 * THZ)
mrtt = 1 * THZ;
}
if (mrtt > 0 && mrtt < TCP_RTT_MAX)
- tcp_estimate_rtt (tc, mrtt);
+ {
+ /* First measurement as per RFC 6298 */
+ tc->srtt = mrtt;
+ tc->rttvar = mrtt >> 1;
+ }
tcp_update_rto (tc);
}
* three segments that have left the network and should've been
* buffered at the receiver XXX */
if (!tcp_opts_sack_permitted (&tc->rcv_opts))
- tc->cwnd += 3 * tc->snd_mss;
+ tc->cwnd += TCP_DUPACK_THRESHOLD * tc->snd_mss;
tc->fr_occurences += 1;
TCP_EVT (TCP_EVT_CC_EVT, tc, 4);
return (tcp_cc_is_spurious_timeout_rxt (tc));
}
-static inline u8
-tcp_should_fastrecover_sack (tcp_connection_t * tc)
-{
- return (tc->sack_sb.lost_bytes
- || ((TCP_DUPACK_THRESHOLD - 1) * tc->snd_mss
- < tc->sack_sb.sacked_bytes));
-}
-
static inline u8
tcp_should_fastrecover (tcp_connection_t * tc, u8 has_sack)
{
return 0;
}
}
- return ((tc->rcv_dupacks == TCP_DUPACK_THRESHOLD)
- || tcp_should_fastrecover_sack (tc));
+ return tc->sack_sb.lost_bytes || tc->rcv_dupacks >= tc->sack_sb.reorder;
}
static int
tcp_connection_init_vars (child);
child->rto = TCP_RTO_MIN;
+ /*
+ * This initializes elog track, must be done before synack.
+ * We also do it before possible tcp_connection_cleanup() as it
+ * generates TCP_EVT_DELETE event.
+ */
+ TCP_EVT (TCP_EVT_SYN_RCVD, child, 1);
+
if (session_stream_accept (&child->connection, lc->c_s_index,
lc->c_thread_index, 0 /* notify */ ))
{
child->tx_fifo_size = transport_tx_fifo_size (&child->connection);
- /* This initializes elog track, must be done before synack */
- TCP_EVT (TCP_EVT_SYN_RCVD, child, 1);
-
tcp_send_synack (child);
done:
_(FIN_WAIT_2, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(FIN_WAIT_2, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
+ _(FIN_WAIT_2, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(CLOSE_WAIT, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(CLOSE_WAIT, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
_(CLOSE_WAIT, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(CLOSE_WAIT, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
+ _(CLOSE_WAIT, TCP_FLAG_SYN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(LAST_ACK, 0, TCP_INPUT_NEXT_DROP, TCP_ERROR_SEGMENT_INVALID);
_(LAST_ACK, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(LAST_ACK, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);