+ 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] = 0;
+
+ 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))