aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/tcp/tcp_input.c
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2017-07-13 01:24:57 -0400
committerFlorin Coras <florin.coras@gmail.com>2017-07-15 17:43:40 +0000
commit3eb5062b40feb3002de09a3caff86232d6e1adea (patch)
tree70eaa2d3c021a7b4bf067557a0d62c55dc447320 /src/vnet/tcp/tcp_input.c
parent213b5aae860c2a9d5de8d4d070d0d2091af699f5 (diff)
Fixes and improved tcp/session debugging
- Fix rx sack option parsing - Add session sack scoreboard tracing and replaying - Add svm fifo tracing and replaying - Scoreboard/svm fifo ooo segment reception fixes - Improved overall debugging Change-Id: Ieae07eba355e66f5935253232bb00f2dfb7ece00 Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/vnet/tcp/tcp_input.c')
-rw-r--r--src/vnet/tcp/tcp_input.c114
1 files changed, 79 insertions, 35 deletions
diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c
index 45db0da69c6..bc7d9015789 100644
--- a/src/vnet/tcp/tcp_input.c
+++ b/src/vnet/tcp/tcp_input.c
@@ -206,8 +206,8 @@ tcp_options_parse (tcp_header_t * th, tcp_options_t * to)
vec_reset_length (to->sacks);
for (j = 0; j < to->n_sack_blocks; j++)
{
- b.start = clib_net_to_host_u32 (*(u32 *) (data + 2 + 4 * j));
- b.end = clib_net_to_host_u32 (*(u32 *) (data + 6 + 4 * j));
+ b.start = clib_net_to_host_u32 (*(u32 *) (data + 2 + 8 * j));
+ b.end = clib_net_to_host_u32 (*(u32 *) (data + 6 + 8 * j));
vec_add1 (to->sacks, b);
}
break;
@@ -540,6 +540,10 @@ scoreboard_remove_hole (sack_scoreboard_t * sb, sack_scoreboard_hole_t * hole)
if (scoreboard_hole_index (sb, hole) == sb->cur_rxt_hole)
sb->cur_rxt_hole = TCP_INVALID_SACK_HOLE_INDEX;
+ /* Poison the entry */
+ if (CLIB_DEBUG > 0)
+ memset (hole, 0xfe, sizeof (*hole));
+
pool_put (sb->holes, hole);
}
@@ -555,7 +559,7 @@ scoreboard_insert_hole (sack_scoreboard_t * sb, u32 prev_index,
hole->start = start;
hole->end = end;
- hole_index = hole - sb->holes;
+ hole_index = scoreboard_hole_index (sb, hole);
prev = scoreboard_get_hole (sb, prev_index);
if (prev)
@@ -680,12 +684,30 @@ scoreboard_next_rxt_hole (sack_scoreboard_t * sb,
}
void
-scoreboard_init_high_rxt (sack_scoreboard_t * sb)
+scoreboard_init_high_rxt (sack_scoreboard_t * sb, u32 seq)
{
sack_scoreboard_hole_t *hole;
hole = scoreboard_first_hole (sb);
- sb->high_rxt = hole->start;
- sb->cur_rxt_hole = sb->head;
+ if (hole)
+ {
+ seq = seq_gt (seq, hole->start) ? seq : hole->start;
+ sb->cur_rxt_hole = sb->head;
+ }
+ sb->high_rxt = seq;
+}
+
+/**
+ * Test that scoreboard is sane after recovery
+ *
+ * Returns 1 if scoreboard is empty or if first hole beyond
+ * snd_una.
+ */
+u8
+tcp_scoreboard_is_sane_post_recovery (tcp_connection_t * tc)
+{
+ sack_scoreboard_hole_t *hole;
+ hole = scoreboard_first_hole (&tc->sack_sb);
+ return (!hole || seq_geq (hole->start, tc->snd_una));
}
void
@@ -712,7 +734,7 @@ tcp_rcv_sacks (tcp_connection_t * tc, u32 ack)
{
if (seq_lt (blk->start, blk->end)
&& seq_gt (blk->start, tc->snd_una)
- && seq_gt (blk->start, ack) && seq_leq (blk->end, tc->snd_nxt))
+ && seq_gt (blk->start, ack) && seq_leq (blk->end, tc->snd_una_max))
{
blk++;
continue;
@@ -731,6 +753,8 @@ tcp_rcv_sacks (tcp_connection_t * tc, u32 ack)
if (vec_len (tc->rcv_opts.sacks) == 0)
return;
+ tcp_scoreboard_trace_add (tc, ack);
+
/* Make sure blocks are ordered */
for (i = 0; i < vec_len (tc->rcv_opts.sacks); i++)
for (j = i + 1; j < vec_len (tc->rcv_opts.sacks); j++)
@@ -797,7 +821,7 @@ tcp_rcv_sacks (tcp_connection_t * tc, u32 ack)
sb->last_bytes_delivered +=
next_hole->start - hole->end;
}
- else if (!next_hole)
+ else
{
ASSERT (seq_geq (sb->high_sacked, ack));
sb->snd_una_adv = sb->high_sacked - ack;
@@ -824,12 +848,14 @@ tcp_rcv_sacks (tcp_connection_t * tc, u32 ack)
if (seq_lt (blk->end, hole->end))
{
hole_index = scoreboard_hole_index (sb, hole);
- scoreboard_insert_hole (sb, hole_index, blk->end, hole->end);
+ next_hole = scoreboard_insert_hole (sb, hole_index, blk->end,
+ hole->end);
/* Pool might've moved */
hole = scoreboard_get_hole (sb, hole_index);
hole->end = blk->start;
blk_index++;
+ ASSERT (hole->next == scoreboard_hole_index (sb, next_hole));
}
else if (seq_lt (blk->start, hole->end))
{
@@ -957,7 +983,7 @@ tcp_cc_recover (tcp_connection_t * tc)
ASSERT (tc->rto_boff == 0);
ASSERT (!tcp_in_cong_recovery (tc));
-
+ ASSERT (tcp_scoreboard_is_sane_post_recovery (tc));
TCP_EVT_DBG (TCP_EVT_CC_EVT, tc, 3);
return 0;
}
@@ -965,7 +991,7 @@ tcp_cc_recover (tcp_connection_t * tc)
static void
tcp_cc_update (tcp_connection_t * tc, vlib_buffer_t * b)
{
- ASSERT (!tcp_in_cong_recovery (tc));
+ ASSERT (!tcp_in_cong_recovery (tc) || tcp_is_lost_fin (tc));
/* Congestion avoidance */
tc->cc_algo->rcv_ack (tc);
@@ -1064,10 +1090,10 @@ tcp_cc_handle_event (tcp_connection_t * tc, u32 is_dack)
ASSERT (tc->cwnd >= tc->snd_mss);
/* If cwnd allows, send more data */
- if (tcp_opts_sack_permitted (&tc->rcv_opts)
- && scoreboard_first_hole (&tc->sack_sb))
+ if (tcp_opts_sack_permitted (&tc->rcv_opts))
{
- scoreboard_init_high_rxt (&tc->sack_sb);
+ scoreboard_init_high_rxt (&tc->sack_sb,
+ tc->snd_una + tc->snd_mss);
tcp_fast_retransmit_sack (tc);
}
else
@@ -1134,12 +1160,13 @@ partial_ack:
/* Remove retransmitted bytes that have been delivered */
ASSERT (tc->bytes_acked + tc->sack_sb.snd_una_adv
>= tc->sack_sb.last_bytes_delivered);
- rxt_delivered = tc->bytes_acked + tc->sack_sb.snd_una_adv
- - tc->sack_sb.last_bytes_delivered;
- if (0 && rxt_delivered && seq_gt (tc->sack_sb.high_rxt, tc->snd_una))
+
+ if (seq_lt (tc->snd_una, tc->sack_sb.high_rxt))
{
/* If we have sacks and we haven't gotten an ack beyond high_rxt,
* remove sacked bytes delivered */
+ rxt_delivered = tc->bytes_acked + tc->sack_sb.snd_una_adv
+ - tc->sack_sb.last_bytes_delivered;
ASSERT (tc->snd_rxt_bytes >= rxt_delivered);
tc->snd_rxt_bytes -= rxt_delivered;
}
@@ -1256,6 +1283,18 @@ tcp_rcv_ack (tcp_connection_t * tc, vlib_buffer_t * b,
return 0;
}
+static u8
+tcp_sack_vector_is_sane (sack_block_t * sacks)
+{
+ int i;
+ for (i = 1; i < vec_len (sacks); i++)
+ {
+ if (sacks[i - 1].end == sacks[i].start)
+ return 0;
+ }
+ return 1;
+}
+
/**
* Build SACK list as per RFC2018.
*
@@ -1316,6 +1355,9 @@ tcp_update_sack_list (tcp_connection_t * tc, u32 start, u32 end)
/* Replace old vector with new one */
vec_free (tc->snd_sacks);
tc->snd_sacks = new_list;
+
+ /* Segments should not 'touch' */
+ ASSERT (tcp_sack_vector_is_sane (tc->snd_sacks));
}
/** Enqueue data for delivery to application */
@@ -1330,7 +1372,6 @@ tcp_session_enqueue_data (tcp_connection_t * tc, vlib_buffer_t * b,
/* Pure ACK. Update rcv_nxt and be done. */
if (PREDICT_FALSE (data_len == 0))
{
- tc->rcv_nxt = vnet_buffer (b)->tcp.seq_end;
return TCP_ERROR_PURE_ACK;
}
@@ -1385,7 +1426,7 @@ tcp_session_enqueue_ooo (tcp_connection_t * tc, vlib_buffer_t * b,
u16 data_len)
{
stream_session_t *s0;
- int rv;
+ int rv, offset;
ASSERT (seq_gt (vnet_buffer (b)->tcp.seq_number, tc->rcv_nxt));
@@ -1421,12 +1462,12 @@ tcp_session_enqueue_ooo (tcp_connection_t * tc, vlib_buffer_t * b,
newest = svm_fifo_newest_ooo_segment (s0->server_rx_fifo);
if (newest)
{
- start =
- tc->rcv_nxt + ooo_segment_offset (s0->server_rx_fifo, newest);
+ offset = ooo_segment_offset (s0->server_rx_fifo, newest);
+ ASSERT (offset <= vnet_buffer (b)->tcp.seq_number - tc->rcv_nxt);
+ start = tc->rcv_nxt + offset;
end = start + ooo_segment_length (s0->server_rx_fifo, newest);
tcp_update_sack_list (tc, start, end);
-
- ASSERT (seq_gt (start, tc->rcv_nxt));
+ svm_fifo_newest_ooo_segment_reset (s0->server_rx_fifo);
}
}
@@ -2736,12 +2777,12 @@ tcp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
/* lookup session */
tc0 =
(tcp_connection_t *)
- stream_session_lookup_transport4 (&ip40->dst_address,
- &ip40->src_address,
- tcp0->dst_port,
- tcp0->src_port,
- SESSION_TYPE_IP4_TCP,
- my_thread_index);
+ stream_session_lookup_transport_wt4 (&ip40->dst_address,
+ &ip40->src_address,
+ tcp0->dst_port,
+ tcp0->src_port,
+ SESSION_TYPE_IP4_TCP,
+ my_thread_index);
}
else
{
@@ -2754,12 +2795,12 @@ tcp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
tc0 =
(tcp_connection_t *)
- stream_session_lookup_transport6 (&ip60->src_address,
- &ip60->dst_address,
- tcp0->src_port,
- tcp0->dst_port,
- SESSION_TYPE_IP6_TCP,
- my_thread_index);
+ stream_session_lookup_transport_wt6 (&ip60->src_address,
+ &ip60->dst_address,
+ tcp0->src_port,
+ tcp0->dst_port,
+ SESSION_TYPE_IP6_TCP,
+ my_thread_index);
}
/* Length check */
@@ -2931,6 +2972,8 @@ do { \
_(ESTABLISHED, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_ESTABLISHED,
TCP_ERROR_NONE);
_(ESTABLISHED, TCP_FLAG_SYN, TCP_INPUT_NEXT_ESTABLISHED, TCP_ERROR_NONE);
+ _(ESTABLISHED, TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_ESTABLISHED,
+ TCP_ERROR_NONE);
/* ACK or FIN-ACK to our FIN */
_(FIN_WAIT_1, TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(FIN_WAIT_1, TCP_FLAG_ACK | TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS,
@@ -2954,6 +2997,7 @@ do { \
_(TIME_WAIT, TCP_FLAG_FIN, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(TIME_WAIT, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RCV_PROCESS,
TCP_ERROR_NONE);
+ _(TIME_WAIT, TCP_FLAG_RST, TCP_INPUT_NEXT_RCV_PROCESS, TCP_ERROR_NONE);
_(CLOSED, TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET, TCP_ERROR_CONNECTION_CLOSED);
_(CLOSED, TCP_FLAG_RST, TCP_INPUT_NEXT_DROP, TCP_ERROR_CONNECTION_CLOSED);
_(CLOSED, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET,