+nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
+ u8 is_output)
+{
+ snat_main_t *sm = &snat_main;
+ u32 next_worker_index = sm->first_worker_index;
+ u32 hash;
+
+ clib_bihash_kv_16_8_t kv16, value16;
+ snat_main_per_thread_data_t *tsm;
+ udp_header_t *udp;
+
+ if (PREDICT_FALSE (is_output))
+ {
+ u32 fib_index = sm->outside_fib_index;
+ nat_outside_fib_t *outside_fib;
+ fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
+ fib_prefix_t pfx = {
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_len = 32,
+ .fp_addr = {
+ .ip4.as_u32 = ip->dst_address.as_u32,
+ }
+ ,
+ };
+
+ udp = ip4_next_header (ip);
+
+ switch (vec_len (sm->outside_fibs))
+ {
+ case 0:
+ fib_index = sm->outside_fib_index;
+ break;
+ case 1:
+ fib_index = sm->outside_fibs[0].fib_index;
+ break;
+ default:
+ /* *INDENT-OFF* */
+ vec_foreach (outside_fib, sm->outside_fibs)
+ {
+ fei = fib_table_lookup (outside_fib->fib_index, &pfx);
+ if (FIB_NODE_INDEX_INVALID != fei)
+ {
+ if (fib_entry_get_resolving_interface (fei) != ~0)
+ {
+ fib_index = outside_fib->fib_index;
+ break;
+ }
+ }
+ }
+ /* *INDENT-ON* */
+ break;
+ }
+
+ make_ed_kv (&kv16, &ip->src_address, &ip->dst_address,
+ ip->protocol, fib_index, udp->src_port, udp->dst_port);
+
+ /* *INDENT-OFF* */
+ vec_foreach (tsm, sm->per_thread_data)
+ {
+ if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
+ &kv16, &value16)))
+ {
+ next_worker_index += tsm->thread_index;
+
+ nat_elog_debug_handoff (
+ "HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
+ next_worker_index, fib_index,
+ clib_net_to_host_u32 (ip->src_address.as_u32),
+ clib_net_to_host_u32 (ip->dst_address.as_u32));
+
+ return next_worker_index;
+ }
+ }
+ /* *INDENT-ON* */
+ }
+
+ hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
+ (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
+
+ if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
+ next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
+ else
+ next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
+
+ if (PREDICT_TRUE (!is_output))
+ {
+ nat_elog_debug_handoff ("HANDOFF IN2OUT",
+ next_worker_index, rx_fib_index,
+ clib_net_to_host_u32 (ip->src_address.as_u32),
+ clib_net_to_host_u32 (ip->dst_address.as_u32));
+ }
+ else
+ {
+ nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE",
+ next_worker_index, rx_fib_index,
+ clib_net_to_host_u32 (ip->src_address.as_u32),
+ clib_net_to_host_u32 (ip->dst_address.as_u32));
+ }
+
+ return next_worker_index;
+}
+
+static u32
+nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index,
+ u8 is_output)