+
+/* Compute TCP checksum in software when offloading is disabled for a connection */
+u16
+ip6_tcp_compute_checksum_custom (vlib_main_t * vm, vlib_buffer_t * p0,
+ ip46_address_t * src, ip46_address_t * dst)
+{
+ ip_csum_t sum0;
+ u16 payload_length_host_byte_order;
+ u32 i;
+
+ /* Initialize checksum with ip header. */
+ sum0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p0)) +
+ clib_host_to_net_u16 (IP_PROTOCOL_TCP);
+ payload_length_host_byte_order = vlib_buffer_length_in_chain (vm, p0);
+
+ for (i = 0; i < ARRAY_LEN (src->ip6.as_uword); i++)
+ {
+ sum0 = ip_csum_with_carry
+ (sum0, clib_mem_unaligned (&src->ip6.as_uword[i], uword));
+ sum0 = ip_csum_with_carry
+ (sum0, clib_mem_unaligned (&dst->ip6.as_uword[i], uword));
+ }
+
+ return ip_calculate_l4_checksum (vm, p0, sum0,
+ payload_length_host_byte_order, NULL, 0,
+ NULL);
+}
+
+u16
+ip4_tcp_compute_checksum_custom (vlib_main_t * vm, vlib_buffer_t * p0,
+ ip46_address_t * src, ip46_address_t * dst)
+{
+ ip_csum_t sum0;
+ u32 payload_length_host_byte_order;
+
+ payload_length_host_byte_order = vlib_buffer_length_in_chain (vm, p0);
+ sum0 =
+ clib_host_to_net_u32 (payload_length_host_byte_order +
+ (IP_PROTOCOL_TCP << 16));
+
+ sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&src->ip4, u32));
+ sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&dst->ip4, u32));
+
+ return ip_calculate_l4_checksum (vm, p0, sum0,
+ payload_length_host_byte_order, NULL, 0,
+ NULL);
+}
+
+static inline u16
+tcp_compute_checksum (tcp_connection_t * tc, vlib_buffer_t * b)
+{
+ u16 checksum = 0;
+ if (PREDICT_FALSE (tc->cfg_flags & TCP_CFG_F_NO_CSUM_OFFLOAD))
+ {
+ tcp_worker_ctx_t *wrk = tcp_get_worker (tc->c_thread_index);
+ vlib_main_t *vm = wrk->vm;
+
+ if (tc->c_is_ip4)
+ checksum = ip4_tcp_compute_checksum_custom
+ (vm, b, &tc->c_lcl_ip, &tc->c_rmt_ip);
+ else
+ checksum = ip6_tcp_compute_checksum_custom
+ (vm, b, &tc->c_lcl_ip, &tc->c_rmt_ip);
+ }
+ else
+ {
+ b->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM;
+ }
+ return checksum;
+}
+