+ /* worker by outside port */
+ next_worker_index = sm->first_worker_index;
+ next_worker_index +=
+ sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
+
+done:
+ nat_elog_debug_handoff ("HANDOFF OUT2IN", 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;
+}
+
+void
+nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
+ ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port,
+ ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
+ u32 fib_index, u16 flags, u32 thread_index)
+{
+ snat_main_t *sm = &snat_main;
+ snat_session_key_t key;
+ snat_user_t *u;
+ snat_session_t *s;
+ clib_bihash_kv_8_8_t kv;
+ f64 now = vlib_time_now (sm->vlib_main);
+ nat_outside_fib_t *outside_fib;
+ fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
+ snat_main_per_thread_data_t *tsm;
+ fib_prefix_t pfx = {
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_len = 32,
+ .fp_addr = {
+ .ip4.as_u32 = eh_addr->as_u32,
+ },
+ };
+
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ key.protocol = proto;
+
+ if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
+ {
+ if (nat_set_outside_address_and_port
+ (sm->addresses, thread_index, &key))
+ return;
+ }
+
+ u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
+ if (!u)
+ return;
+
+ s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
+ if (!s)
+ return;
+
+ s->last_heard = now;
+ s->flags = flags;
+ s->ext_host_addr.as_u32 = eh_addr->as_u32;
+ s->ext_host_port = eh_port;
+ user_session_increment (sm, u, snat_is_session_static (s));
+ switch (vec_len (sm->outside_fibs))
+ {
+ case 0:
+ key.fib_index = sm->outside_fib_index;
+ break;
+ case 1:
+ key.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)
+ {
+ key.fib_index = outside_fib->fib_index;
+ break;
+ }
+ }
+ }
+ /* *INDENT-ON* */
+ break;
+ }
+ s->out2in = key;
+ kv.key = key.as_u64;
+ kv.value = s - tsm->sessions;
+ if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 1))
+ nat_elog_warn ("out2in key add failed");
+
+ key.addr.as_u32 = in_addr->as_u32;
+ key.port = in_port;
+ key.fib_index = fib_index;
+ s->in2out = key;
+ kv.key = key.as_u64;
+ if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 1))
+ nat_elog_warn ("in2out key add failed");
+}
+
+void
+nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
+ u32 ti)
+{
+ snat_main_t *sm = &snat_main;
+ snat_session_key_t key;
+ clib_bihash_kv_8_8_t kv, value;
+ u32 thread_index;
+ snat_session_t *s;
+ snat_main_per_thread_data_t *tsm;
+
+ if (sm->num_workers > 1)
+ thread_index =
+ sm->first_worker_index +
+ (sm->workers[(clib_net_to_host_u16 (out_port) -
+ 1024) / sm->port_per_thread]);
+ else
+ thread_index = sm->num_workers;
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ key.protocol = proto;
+ key.fib_index = fib_index;
+ kv.key = key.as_u64;
+ if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
+ return;
+
+ s = pool_elt_at_index (tsm->sessions, value.value);
+ nat_free_session_data (sm, s, thread_index, 1);
+ nat44_delete_session (sm, s, thread_index);
+}
+
+void
+nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
+ u32 total_pkts, u64 total_bytes, u32 thread_index)
+{
+ snat_main_t *sm = &snat_main;
+ snat_session_key_t key;
+ clib_bihash_kv_8_8_t kv, value;
+ snat_session_t *s;
+ snat_main_per_thread_data_t *tsm;
+
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ key.protocol = proto;
+ key.fib_index = fib_index;
+ kv.key = key.as_u64;
+ if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
+ return;
+
+ s = pool_elt_at_index (tsm->sessions, value.value);
+ s->total_pkts = total_pkts;
+ s->total_bytes = total_bytes;
+}
+
+void
+nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
+ ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port,
+ ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
+ u32 fib_index, u16 flags, u32 thread_index)
+{
+ snat_main_t *sm = &snat_main;
+ snat_session_key_t key;
+ snat_user_t *u;
+ snat_session_t *s;
+ clib_bihash_kv_16_8_t kv;
+ f64 now = vlib_time_now (sm->vlib_main);
+ nat_outside_fib_t *outside_fib;
+ fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
+ snat_main_per_thread_data_t *tsm;
+ fib_prefix_t pfx = {
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_len = 32,
+ .fp_addr = {
+ .ip4.as_u32 = eh_addr->as_u32,
+ },
+ };
+
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ key.protocol = proto;
+
+ if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
+ {
+ if (nat_set_outside_address_and_port
+ (sm->addresses, thread_index, &key))
+ return;
+ }
+
+ key.addr.as_u32 = ehn_addr->as_u32;
+ key.port = ehn_port;
+ if (flags & SNAT_SESSION_FLAG_TWICE_NAT)
+ {
+ if (nat_set_outside_address_and_port
+ (sm->twice_nat_addresses, thread_index, &key))
+ return;
+ }
+
+ u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
+ if (!u)
+ return;
+
+ s = nat_ed_session_alloc (sm, u, thread_index, now);
+ if (!s)
+ return;
+
+ s->last_heard = now;
+ s->flags = flags;
+ s->ext_host_nat_addr.as_u32 = s->ext_host_addr.as_u32 = eh_addr->as_u32;
+ s->ext_host_nat_port = s->ext_host_port = eh_port;
+ if (is_twice_nat_session (s))
+ {
+ s->ext_host_nat_addr.as_u32 = ehn_addr->as_u32;
+ s->ext_host_nat_port = ehn_port;
+ }
+ user_session_increment (sm, u, snat_is_session_static (s));
+ switch (vec_len (sm->outside_fibs))
+ {
+ case 0:
+ key.fib_index = sm->outside_fib_index;
+ break;
+ case 1:
+ key.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)
+ {
+ key.fib_index = outside_fib->fib_index;
+ break;
+ }
+ }
+ }
+ /* *INDENT-ON* */
+ break;
+ }
+ key.addr.as_u32 = out_addr->as_u32;
+ key.port = out_port;
+ s->out2in = key;
+ kv.value = s - tsm->sessions;
+
+ key.addr.as_u32 = in_addr->as_u32;
+ key.port = in_port;
+ key.fib_index = fib_index;
+ s->in2out = key;
+
+ make_ed_kv (&kv, in_addr, &s->ext_host_nat_addr,
+ snat_proto_to_ip_proto (proto), fib_index, in_port,
+ s->ext_host_nat_port);
+ if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
+ nat_elog_warn ("in2out key add failed");
+
+ make_ed_kv (&kv, out_addr, eh_addr, snat_proto_to_ip_proto (proto),
+ s->out2in.fib_index, out_port, eh_port);
+ if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
+ nat_elog_warn ("out2in key add failed");
+}
+
+void
+nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
+ ip4_address_t * eh_addr, u16 eh_port, u8 proto,
+ u32 fib_index, u32 ti)
+{
+ snat_main_t *sm = &snat_main;
+ nat_ed_ses_key_t key;
+ clib_bihash_kv_16_8_t kv, value;
+ u32 thread_index;
+ snat_session_t *s;
+ snat_main_per_thread_data_t *tsm;
+
+ if (sm->num_workers > 1)
+ thread_index =
+ sm->first_worker_index +
+ (sm->workers[(clib_net_to_host_u16 (out_port) -
+ 1024) / sm->port_per_thread]);
+ else
+ thread_index = sm->num_workers;
+ tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
+
+ key.l_addr.as_u32 = out_addr->as_u32;
+ key.l_port = out_port;
+ key.r_addr.as_u32 = eh_addr->as_u32;
+ key.r_port = eh_port;
+ key.proto = proto;
+ key.fib_index = fib_index;
+ kv.key[0] = key.as_u64[0];
+ kv.key[1] = key.as_u64[1];
+ if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
+ return;