tcp: fix input error counters
[vpp.git] / src / vnet / tcp / tcp_input.c
index ef5a16f..f981351 100755 (executable)
@@ -784,6 +784,8 @@ scoreboard_update_bytes (sack_scoreboard_t * sb, u32 ack, u32 snd_mss)
   if (!right)
     {
       sb->sacked_bytes = sb->high_sacked - ack;
+      sb->last_sacked_bytes = sb->sacked_bytes
+       - (old_sacked - sb->last_bytes_delivered);
       return;
     }
 
@@ -988,7 +990,7 @@ tcp_rcv_sacks (tcp_connection_t * tc, u32 ack)
   sb->last_bytes_delivered = 0;
   sb->rxt_sacked = 0;
 
-  if (!tcp_opts_sack (&tc->rcv_opts)
+  if (!tcp_opts_sack (&tc->rcv_opts) && !sb->sacked_bytes
       && sb->head == TCP_INVALID_SACK_HOLE_INDEX)
     return;
 
@@ -1184,7 +1186,7 @@ tcp_rcv_sacks (tcp_connection_t * tc, u32 ack)
          || sb->is_reneging || sb->holes[sb->head].start == ack);
   ASSERT (sb->last_lost_bytes <= sb->lost_bytes);
   ASSERT ((ack - tc->snd_una) + sb->last_sacked_bytes
-         - sb->last_bytes_delivered >= sb->rxt_sacked || sb->is_reneging);
+         - sb->last_bytes_delivered >= sb->rxt_sacked);
   ASSERT ((ack - tc->snd_una) >= tc->sack_sb.last_bytes_delivered
          || (tc->flags & TCP_CONN_FINSNT));
 
@@ -1459,7 +1461,7 @@ tcp_cc_handle_event (tcp_connection_t * tc, tcp_rate_sample_t * rs,
          tc->rcv_dupacks += 1;
          TCP_EVT (TCP_EVT_DUPACK_RCVD, tc, 1);
        }
-      tc->rxt_delivered = clib_max (tc->rxt_delivered + tc->bytes_acked,
+      tc->rxt_delivered = clib_min (tc->rxt_delivered + tc->bytes_acked,
                                    tc->snd_rxt_bytes);
       if (is_dack)
        tc->prr_delivered += clib_min (tc->snd_mss,
@@ -2027,12 +2029,12 @@ format_tcp_rx_trace (u8 * s, va_list * args)
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
   tcp_rx_trace_t *t = va_arg (*args, tcp_rx_trace_t *);
+  tcp_connection_t *tc = &t->tcp_connection;
   u32 indent = format_get_indent (s);
 
-  s = format (s, "%U\n%U%U",
-             format_tcp_header, &t->tcp_header, 128,
-             format_white_space, indent,
-             format_tcp_connection, &t->tcp_connection, 1);
+  s = format (s, "%U state %U\n%U%U", format_tcp_connection_id, tc,
+             format_tcp_state, tc->state, format_white_space, indent,
+             format_tcp_header, &t->tcp_header, 128);
 
   return s;
 }
@@ -2436,11 +2438,15 @@ tcp_check_tx_offload (tcp_connection_t * tc, int is_ipv4)
     }
 
   lb = load_balance_get (lb_idx);
+  if (PREDICT_FALSE (lb->lb_n_buckets > 1))
+    return;
   dpo = load_balance_get_bucket_i (lb, 0);
 
-  sw_if_idx = dpo->dpoi_index;
-  hw_if = vnet_get_sup_hw_interface (vnm, sw_if_idx);
+  sw_if_idx = dpo_get_urpf (dpo);
+  if (PREDICT_FALSE (sw_if_idx == ~0))
+    return;
 
+  hw_if = vnet_get_sup_hw_interface (vnm, sw_if_idx);
   if (hw_if->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO)
     tc->cfg_flags |= TCP_CFG_F_TSO;
 }
@@ -3215,6 +3221,18 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
       n_left_from -= 1;
 
       b0 = vlib_get_buffer (vm, bi0);
+
+      if (is_ip4)
+       {
+         ip40 = vlib_buffer_get_current (b0);
+         th0 = tcp_buffer_hdr (b0);
+       }
+      else
+       {
+         ip60 = vlib_buffer_get_current (b0);
+         th0 = tcp_buffer_hdr (b0);
+       }
+
       lc0 = tcp_listener_get (vnet_buffer (b0)->tcp.connection_index);
       if (PREDICT_FALSE (lc0 == 0))
        {
@@ -3230,17 +3248,6 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          tcp_connection_del (tc0);
        }
 
-      if (is_ip4)
-       {
-         ip40 = vlib_buffer_get_current (b0);
-         th0 = tcp_buffer_hdr (b0);
-       }
-      else
-       {
-         ip60 = vlib_buffer_get_current (b0);
-         th0 = tcp_buffer_hdr (b0);
-       }
-
       /* Create child session. For syn-flood protection use filter */
 
       /* 1. first check for an RST: handled in dispatch */
@@ -3572,25 +3579,27 @@ tcp_input_lookup_buffer (vlib_buffer_t * b, u8 thread_index, u32 * error,
 
 static inline void
 tcp_input_dispatch_buffer (tcp_main_t * tm, tcp_connection_t * tc,
-                          vlib_buffer_t * b, u16 * next, u32 * error)
+                          vlib_buffer_t * b, u16 * next,
+                          vlib_node_runtime_t * error_node)
 {
   tcp_header_t *tcp;
+  u32 error;
   u8 flags;
 
   tcp = tcp_buffer_hdr (b);
   flags = tcp->flags & filter_flags;
   *next = tm->dispatch_table[tc->state][flags].next;
-  *error = tm->dispatch_table[tc->state][flags].error;
+  error = tm->dispatch_table[tc->state][flags].error;
   tc->segs_in += 1;
 
-  if (PREDICT_FALSE (*error == TCP_ERROR_DISPATCH
-                    || *next == TCP_INPUT_NEXT_RESET))
+  if (PREDICT_FALSE (error != TCP_ERROR_NONE))
     {
       /* Overload tcp flags to store state */
       tcp_state_t state = tc->state;
       vnet_buffer (b)->tcp.flags = tc->state;
 
-      if (*error == TCP_ERROR_DISPATCH)
+      b->error = error_node->errors[error];
+      if (error == TCP_ERROR_DISPATCH)
        clib_warning ("tcp conn %u disp error state %U flags %U",
                      tc->c_c_index, format_tcp_state, state,
                      format_tcp_flags, (int) flags);
@@ -3605,9 +3614,11 @@ tcp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
   tcp_main_t *tm = vnet_get_tcp_main ();
   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
   u16 nexts[VLIB_FRAME_SIZE], *next;
+  vlib_node_runtime_t *error_node;
 
   tcp_set_time_now (tcp_get_worker (thread_index));
 
+  error_node = vlib_node_get_runtime (vm, tcp_node_index (input, is_ip4));
   from = vlib_frame_vector_args (frame);
   n_left_from = frame->n_vectors;
   vlib_get_buffers (vm, from, bufs, n_left_from);
@@ -3643,8 +3654,8 @@ tcp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
          vnet_buffer (b[0])->tcp.connection_index = tc0->c_c_index;
          vnet_buffer (b[1])->tcp.connection_index = tc1->c_c_index;
 
-         tcp_input_dispatch_buffer (tm, tc0, b[0], &next[0], &error0);
-         tcp_input_dispatch_buffer (tm, tc1, b[1], &next[1], &error1);
+         tcp_input_dispatch_buffer (tm, tc0, b[0], &next[0], error_node);
+         tcp_input_dispatch_buffer (tm, tc1, b[1], &next[1], error_node);
        }
       else
        {
@@ -3652,19 +3663,25 @@ tcp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
            {
              ASSERT (tcp_lookup_is_valid (tc0, b[0], tcp_buffer_hdr (b[0])));
              vnet_buffer (b[0])->tcp.connection_index = tc0->c_c_index;
-             tcp_input_dispatch_buffer (tm, tc0, b[0], &next[0], &error0);
+             tcp_input_dispatch_buffer (tm, tc0, b[0], &next[0], error_node);
            }
          else
-           tcp_input_set_error_next (tm, &next[0], &error0, is_ip4);
+           {
+             tcp_input_set_error_next (tm, &next[0], &error0, is_ip4);
+             b[0]->error = error_node->errors[error0];
+           }
 
          if (PREDICT_TRUE (tc1 != 0))
            {
              ASSERT (tcp_lookup_is_valid (tc1, b[1], tcp_buffer_hdr (b[1])));
              vnet_buffer (b[1])->tcp.connection_index = tc1->c_c_index;
-             tcp_input_dispatch_buffer (tm, tc1, b[1], &next[1], &error1);
+             tcp_input_dispatch_buffer (tm, tc1, b[1], &next[1], error_node);
            }
          else
-           tcp_input_set_error_next (tm, &next[1], &error1, is_ip4);
+           {
+             tcp_input_set_error_next (tm, &next[1], &error1, is_ip4);
+             b[1]->error = error_node->errors[error1];
+           }
        }
 
       b += 2;
@@ -3689,10 +3706,13 @@ tcp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
        {
          ASSERT (tcp_lookup_is_valid (tc0, b[0], tcp_buffer_hdr (b[0])));
          vnet_buffer (b[0])->tcp.connection_index = tc0->c_c_index;
-         tcp_input_dispatch_buffer (tm, tc0, b[0], &next[0], &error0);
+         tcp_input_dispatch_buffer (tm, tc0, b[0], &next[0], error_node);
        }
       else
-       tcp_input_set_error_next (tm, &next[0], &error0, is_ip4);
+       {
+         tcp_input_set_error_next (tm, &next[0], &error0, is_ip4);
+         b[0]->error = error_node->errors[error0];
+       }
 
       b += 1;
       next += 1;
@@ -3853,7 +3873,7 @@ do {                                                              \
   _(LISTEN, TCP_FLAG_FIN | TCP_FLAG_RST, TCP_INPUT_NEXT_DROP,
     TCP_ERROR_SEGMENT_INVALID);
   _(LISTEN, TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_DROP,
-    TCP_ERROR_NONE);
+    TCP_ERROR_SEGMENT_INVALID);
   _(LISTEN, TCP_FLAG_FIN | TCP_FLAG_SYN, TCP_INPUT_NEXT_DROP,
     TCP_ERROR_SEGMENT_INVALID);
   _(LISTEN, TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_ACK, TCP_INPUT_NEXT_DROP,
@@ -4040,10 +4060,10 @@ do {                                                            \
   _(CLOSED, TCP_FLAG_RST, TCP_INPUT_NEXT_DROP, TCP_ERROR_CONNECTION_CLOSED);
   _(CLOSED, TCP_FLAG_RST | TCP_FLAG_ACK, TCP_INPUT_NEXT_DROP,
     TCP_ERROR_CONNECTION_CLOSED);
-  _(CLOSED, TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET, TCP_ERROR_NONE);
-  _(CLOSED, TCP_FLAG_SYN, TCP_INPUT_NEXT_RESET, TCP_ERROR_NONE);
+  _(CLOSED, TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET, TCP_ERROR_CONNECTION_CLOSED);
+  _(CLOSED, TCP_FLAG_SYN, TCP_INPUT_NEXT_RESET, TCP_ERROR_CONNECTION_CLOSED);
   _(CLOSED, TCP_FLAG_FIN | TCP_FLAG_ACK, TCP_INPUT_NEXT_RESET,
-    TCP_ERROR_NONE);
+    TCP_ERROR_CONNECTION_CLOSED);
 #undef _
 }