+ tcp_connection_t *tc;
+ tcp_tx_trace_t *t;
+ vlib_buffer_t *b;
+ tcp_header_t *th;
+ int i;
+
+ for (i = 0; i < n_bufs; i++)
+ {
+ b = vlib_get_buffer (vm, to_next[i]);
+ if (!(b->flags & VLIB_BUFFER_IS_TRACED))
+ continue;
+ th = vlib_buffer_get_current (b);
+ tc = tcp_connection_get (vnet_buffer (b)->tcp.connection_index,
+ vm->thread_index);
+ t = vlib_add_trace (vm, node, b, sizeof (*t));
+ clib_memcpy_fast (&t->tcp_header, th, sizeof (t->tcp_header));
+ clib_memcpy_fast (&t->tcp_connection, tc, sizeof (t->tcp_connection));
+ }
+}
+
+always_inline void
+tcp_output_push_ip (vlib_main_t * vm, vlib_buffer_t * b0,
+ tcp_connection_t * tc0, u8 is_ip4)
+{
+ TCP_EVT (TCP_EVT_OUTPUT, tc0,
+ ((tcp_header_t *) vlib_buffer_get_current (b0))->flags,
+ b0->current_length);
+
+ if (is_ip4)
+ vlib_buffer_push_ip4 (vm, b0, &tc0->c_lcl_ip4, &tc0->c_rmt_ip4,
+ IP_PROTOCOL_TCP, tcp_csum_offload (tc0));
+ else
+ vlib_buffer_push_ip6_custom (vm, b0, &tc0->c_lcl_ip6, &tc0->c_rmt_ip6,
+ IP_PROTOCOL_TCP, tc0->ipv6_flow_label);
+}
+
+always_inline void
+tcp_check_if_gso (tcp_connection_t * tc, vlib_buffer_t * b)
+{
+ if (PREDICT_TRUE (!(tc->cfg_flags & TCP_CFG_F_TSO)))
+ return;
+
+ u16 data_len = b->current_length - sizeof (tcp_header_t) - tc->snd_opts_len;
+
+ if (PREDICT_FALSE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
+ data_len += b->total_length_not_including_first_buffer;
+
+ if (PREDICT_TRUE (data_len <= tc->snd_mss))
+ return;
+ else
+ {
+ ASSERT ((b->flags & VNET_BUFFER_F_L3_HDR_OFFSET_VALID) != 0);
+ ASSERT ((b->flags & VNET_BUFFER_F_L4_HDR_OFFSET_VALID) != 0);
+ b->flags |= VNET_BUFFER_F_GSO;
+ vnet_buffer2 (b)->gso_l4_hdr_sz =
+ sizeof (tcp_header_t) + tc->snd_opts_len;
+ vnet_buffer2 (b)->gso_size = tc->snd_mss;
+ }
+}
+
+always_inline void
+tcp_output_handle_packet (tcp_connection_t * tc0, vlib_buffer_t * b0,
+ vlib_node_runtime_t * error_node, u16 * next0,
+ u8 is_ip4)
+{
+ /* If next_index is not drop use it */
+ if (tc0->next_node_index)
+ {
+ *next0 = tc0->next_node_index;
+ vnet_buffer (b0)->tcp.next_node_opaque = tc0->next_node_opaque;
+ }
+ else
+ {
+ *next0 = TCP_OUTPUT_NEXT_IP_LOOKUP;
+ }
+
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = tc0->c_fib_index;
+ vnet_buffer (b0)->sw_if_index[VLIB_RX] = tc0->sw_if_index;
+
+ if (!is_ip4)
+ {
+ u32 error0 = 0;
+
+ if (PREDICT_FALSE (ip6_address_is_link_local_unicast (&tc0->c_rmt_ip6)))
+ tcp_output_handle_link_local (tc0, b0, next0, &error0);
+
+ if (PREDICT_FALSE (error0))
+ {
+ b0->error = error_node->errors[error0];
+ return;
+ }
+ }
+
+ tc0->segs_out += 1;