X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fnat.c;h=3856add419f717d939c5e40e4869c8ae2771979c;hb=34931eb47;hp=c2c812d114b48f8e3db152964e7ae80555074fe4;hpb=fd0d50879f475a1b15cedb4ab49059a02c45ccfd;p=vpp.git diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index c2c812d114b..3856add419f 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -175,7 +176,8 @@ VLIB_PLUGIN_REGISTER () = { /* *INDENT-ON* */ void -nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) +nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index, + u8 is_ha) { snat_session_key_t key; clib_bihash_kv_8_8_t kv; @@ -238,12 +240,13 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)) nat_log_warn ("in2out_ed key del failed"); - nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index, - &s->in2out.addr, s->in2out.port, - &s->ext_host_nat_addr, s->ext_host_nat_port, - &s->out2in.addr, s->out2in.port, - &s->ext_host_addr, s->ext_host_port, - s->in2out.protocol, is_twice_nat_session (s)); + if (!is_ha) + nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index, + &s->in2out.addr, s->in2out.port, + &s->ext_host_nat_addr, s->ext_host_nat_port, + &s->out2in.addr, s->out2in.port, + &s->ext_host_addr, s->ext_host_port, + s->in2out.protocol, is_twice_nat_session (s)); } else { @@ -254,21 +257,31 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0)) nat_log_warn ("out2in key del failed"); - nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index, - &s->in2out.addr, s->in2out.port, - &s->out2in.addr, s->out2in.port, - s->in2out.protocol); + if (!is_ha) + nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index, + &s->in2out.addr, s->in2out.port, + &s->out2in.addr, s->out2in.port, + s->in2out.protocol); } if (snat_is_unk_proto_session (s)) return; - /* log NAT event */ - snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32, - s->out2in.addr.as_u32, - s->in2out.protocol, - s->in2out.port, - s->out2in.port, s->in2out.fib_index); + if (!is_ha) + { + /* log NAT event */ + snat_ipfix_logging_nat44_ses_delete (thread_index, + s->in2out.addr.as_u32, + s->out2in.addr.as_u32, + s->in2out.protocol, + s->in2out.port, + s->out2in.port, + s->in2out.fib_index); + + nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr, + s->ext_host_port, s->out2in.protocol, s->out2in.fib_index, + thread_index); + } /* Twice NAT address and port for external host */ if (is_twice_nat_session (s)) @@ -336,7 +349,7 @@ nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index, snat_session_t * nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u, - u32 thread_index) + u32 thread_index, f64 now) { snat_session_t *s; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; @@ -367,7 +380,7 @@ nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u, /* Get the session */ s = pool_elt_at_index (tsm->sessions, session_index); - nat_free_session_data (sm, s, thread_index); + nat_free_session_data (sm, s, thread_index, 0); if (snat_is_session_static (s)) u->nstaticsessions--; else @@ -404,6 +417,8 @@ nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u, pool_elts (tsm->sessions)); } + s->ha_last_refreshed = now; + return s; } @@ -430,7 +445,7 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index, { clib_dlist_addtail (tsm->list_pool, u->sessions_per_user_list_head_index, oldest_index); - nat_free_session_data (sm, s, thread_index); + nat_free_session_data (sm, s, thread_index, 0); if (snat_is_session_static (s)) u->nstaticsessions--; else @@ -454,7 +469,7 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index, nat_log_warn ("max translations per user %U", format_ip4_address, &u->addr); snat_ipfix_logging_max_entries_per_user - (sm->max_translations_per_user, u->addr.as_u32); + (thread_index, sm->max_translations_per_user, u->addr.as_u32); return 0; } else @@ -481,6 +496,8 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index, pool_elts (tsm->sessions)); } + s->ha_last_refreshed = now; + return s; } @@ -962,7 +979,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, continue; nat_free_session_data (sm, s, - tsm - sm->per_thread_data); + tsm - sm->per_thread_data, 0); nat44_delete_session (sm, s, tsm - sm->per_thread_data); if (!addr_only && !sm->endpoint_dependent) @@ -1086,7 +1103,7 @@ snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, continue; nat_free_session_data (sm, s, - tsm - sm->per_thread_data); + tsm - sm->per_thread_data, 0); nat44_delete_session (sm, s, tsm - sm->per_thread_data); if (!addr_only && !sm->endpoint_dependent) @@ -1395,7 +1412,7 @@ nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, (clib_net_to_host_u16 (s->in2out.port) != local->port)) continue; - nat_free_session_data (sm, s, tsm - sm->per_thread_data); + nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); nat44_delete_session (sm, s, tsm - sm->per_thread_data); } } @@ -1549,7 +1566,7 @@ nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port, match_local->port)) continue; - nat_free_session_data (sm, s, tsm - sm->per_thread_data); + nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); nat44_delete_session (sm, s, tsm - sm->per_thread_data); } } @@ -1575,6 +1592,8 @@ nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port, })); /* *INDENT-ON* */ + ASSERT (vec_len (locals) > 1); + local = pool_elt_at_index (m->locals, locals[0]); local->prefix = local->probability; for (i = 1; i < vec_len (locals); i++) @@ -1657,7 +1676,7 @@ snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm, pool_foreach (ses, tsm->sessions, ({ if (ses->out2in.addr.as_u32 == addr.as_u32) { - nat_free_session_data (sm, ses, tsm - sm->per_thread_data); + nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0); vec_add1 (ses_to_be_removed, ses - tsm->sessions); } })); @@ -1766,7 +1785,7 @@ snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) { if (is_del) { - outside_fib->refcount--; + outside_fib->refcount--; if (!outside_fib->refcount) vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); } @@ -1966,6 +1985,10 @@ snat_interface_add_del_output_feature (u32 sw_if_index, snat_interface_t *i; snat_address_t *ap; snat_static_mapping_t *m; + nat_outside_fib_t *outside_fib; + u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, + sw_if_index); + if (sm->deterministic || (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))) @@ -1979,6 +2002,34 @@ snat_interface_add_del_output_feature (u32 sw_if_index, })); /* *INDENT-ON* */ + if (!is_inside) + { + /* *INDENT-OFF* */ + vec_foreach (outside_fib, sm->outside_fibs) + { + if (outside_fib->fib_index == fib_index) + { + if (is_del) + { + outside_fib->refcount--; + if (!outside_fib->refcount) + vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); + } + else + outside_fib->refcount++; + goto feature_set; + } + } + /* *INDENT-ON* */ + if (!is_del) + { + vec_add2 (sm->outside_fibs, outside_fib, 1); + outside_fib->refcount = 1; + outside_fib->fib_index = fib_index; + } + } + +feature_set: if (is_inside) { if (sm->endpoint_dependent) @@ -2109,6 +2160,65 @@ snat_set_workers (uword * bitmap) return 0; } +static void +snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index, + u32 old_fib_index) +{ + snat_main_t *sm = &snat_main; + nat_outside_fib_t *outside_fib; + snat_interface_t *i; + u8 is_add = 1; + + if (new_fib_index == old_fib_index) + return; + + if (!vec_len (sm->outside_fibs)) + return; + + pool_foreach (i, sm->interfaces, ( + { + if (i->sw_if_index == sw_if_index) + { + if (!(nat_interface_is_outside (i))) + return;} + } + )); + vec_foreach (outside_fib, sm->outside_fibs) + { + if (outside_fib->fib_index == old_fib_index) + { + outside_fib->refcount--; + if (!outside_fib->refcount) + vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); + break; + } + } + + vec_foreach (outside_fib, sm->outside_fibs) + { + if (outside_fib->fib_index == new_fib_index) + { + outside_fib->refcount++; + is_add = 0; + break; + } + } + + if (is_add) + { + vec_add2 (sm->outside_fibs, outside_fib, 1); + outside_fib->refcount = 1; + outside_fib->fib_index = new_fib_index; + } +} + +static void +snat_ip4_table_bind (ip4_main_t * im, + uword opaque, + u32 sw_if_index, u32 new_fib_index, u32 old_fib_index) +{ + snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index); +} static void snat_ip4_add_del_interface_address_cb (ip4_main_t * im, @@ -2146,7 +2256,7 @@ snat_init (vlib_main_t * vm) uword *bitmap = 0; u32 i; ip4_add_del_interface_address_callback_t cb4; - vlib_node_t *error_drop_node; + vlib_node_t *node; sm->vlib_main = vm; sm->vnet_main = vnet_get_main (); @@ -2168,10 +2278,63 @@ snat_init (vlib_main_t * vm) sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT; sm->forwarding_enabled = 0; sm->log_class = vlib_log_register_class ("nat", 0); - error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); - sm->error_node_index = error_drop_node->index; sm->mss_clamping = 0; + node = vlib_get_node_by_name (vm, (u8 *) "error-drop"); + sm->error_node_index = node->index; + + node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out"); + sm->in2out_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output"); + sm->in2out_output_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast"); + sm->in2out_fast_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath"); + sm->in2out_slowpath_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath"); + sm->in2out_slowpath_output_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-reass"); + sm->in2out_reass_node_index = node->index; + + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out"); + sm->ed_in2out_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath"); + sm->ed_in2out_slowpath_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-reass"); + sm->ed_in2out_reass_node_index = node->index; + + node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in"); + sm->out2in_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast"); + sm->out2in_fast_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-reass"); + sm->out2in_reass_node_index = node->index; + + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in"); + sm->ed_out2in_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath"); + sm->ed_out2in_slowpath_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-reass"); + sm->ed_out2in_reass_node_index = node->index; + + node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-in2out"); + sm->det_in2out_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-out2in"); + sm->det_out2in_node_index = node->index; + + node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning"); + sm->hairpinning_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst"); + sm->hairpin_dst_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src"); + sm->hairpin_src_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpinning"); + sm->ed_hairpinning_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-dst"); + sm->ed_hairpin_dst_node_index = node->index; + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src"); + sm->ed_hairpin_src_node_index = node->index; + p = hash_get_mem (tm->thread_registrations_by_name, "workers"); if (p) { @@ -2235,7 +2398,12 @@ snat_init (vlib_main_t * vm) dslite_init (vm); - nat66_init (); + nat66_init (vm); + + ip4_table_bind_callback_t cbt4 = { + .function = snat_ip4_table_bind, + }; + vec_add1 (ip4_main.table_bind_callbacks, cbt4); /* Init virtual fragmenentation reassembly */ return nat_reass_init (vm); @@ -2281,6 +2449,42 @@ snat_free_outside_address_and_port (snat_address_t * addresses, } } +static int +nat_set_outside_address_and_port (snat_address_t * addresses, + u32 thread_index, snat_session_key_t * k) +{ + snat_address_t *a = 0; + u32 address_index; + u16 port_host_byte_order = clib_net_to_host_u16 (k->port); + + for (address_index = 0; address_index < vec_len (addresses); + address_index++) + { + if (addresses[address_index].addr.as_u32 != k->addr.as_u32) + continue; + + a = addresses + address_index; + switch (k->protocol) + { +#define _(N, j, n, s) \ + case SNAT_PROTOCOL_##N: \ + if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, port_host_byte_order)) \ + return VNET_API_ERROR_INSTANCE_IN_USE; \ + clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, port_host_byte_order, 1); \ + a->busy_##n##_ports_per_thread[thread_index]++; \ + a->busy_##n##_ports++; \ + return 0; + foreach_snat_protocol +#undef _ + default: + nat_log_info ("unknown protocol"); + return 1; + } + } + + return VNET_API_ERROR_NO_SUCH_ENTRY; +} + int snat_static_mapping_match (snat_main_t * sm, snat_session_key_t match, @@ -2523,7 +2727,7 @@ nat_alloc_addr_and_port_default (snat_address_t * addresses, } /* Totally out of translations to use... */ - snat_ipfix_logging_addresses_exhausted (0); + snat_ipfix_logging_addresses_exhausted (thread_index, 0); return 1; } @@ -2573,7 +2777,7 @@ nat_alloc_addr_and_port_mape (snat_address_t * addresses, exhausted: /* Totally out of translations to use... */ - snat_ipfix_logging_addresses_exhausted (0); + snat_ipfix_logging_addresses_exhausted (thread_index, 0); return 1; } @@ -2621,7 +2825,7 @@ nat_alloc_addr_and_port_range (snat_address_t * addresses, exhausted: /* Totally out of translations to use... */ - snat_ipfix_logging_addresses_exhausted (0); + snat_ipfix_logging_addresses_exhausted (thread_index, 0); return 1; } @@ -2763,20 +2967,47 @@ snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0) if (PREDICT_FALSE (nat_reass_is_drop_frag (0))) return vlib_get_thread_index (); - if (PREDICT_TRUE (!ip4_is_first_fragment (ip0))) - { - nat_reass_ip4_t *reass; + nat_reass_ip4_t *reass; + reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address, + ip0->fragment_id, ip0->protocol); - reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address, - ip0->fragment_id, ip0->protocol); + if (reass && (reass->thread_index != (u32) ~ 0)) + return reass->thread_index; - if (reass && (reass->thread_index != (u32) ~ 0)) - return reass->thread_index; - else - return vlib_get_thread_index (); + if (ip4_is_first_fragment (ip0)) + { + reass = + nat_ip4_reass_create (ip0->src_address, ip0->dst_address, + ip0->fragment_id, ip0->protocol); + if (!reass) + goto no_reass; + + if (PREDICT_FALSE (pool_elts (sm->static_mappings))) + { + m_key.addr = ip0->dst_address; + m_key.port = clib_net_to_host_u16 (port); + m_key.protocol = proto; + m_key.fib_index = rx_fib_index0; + kv.key = m_key.as_u64; + if (!clib_bihash_search_8_8 + (&sm->static_mapping_by_external, &kv, &value)) + { + m = pool_elt_at_index (sm->static_mappings, value.value); + reass->thread_index = m->workers[0]; + return reass->thread_index; + } + } + reass->thread_index = sm->first_worker_index; + reass->thread_index += + sm->workers[(clib_net_to_host_u16 (port) - 1024) / + sm->port_per_thread]; + return reass->thread_index; } + else + return vlib_get_thread_index (); } +no_reass: /* unknown protocol */ if (PREDICT_FALSE (proto == ~0)) { @@ -2928,6 +3159,334 @@ nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index) 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_log_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_log_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_log_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_log_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; + + 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_ed_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; + nat_ed_ses_key_t key; + clib_bihash_kv_16_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.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; + + s = pool_elt_at_index (tsm->sessions, value.value); + s->total_pkts = total_pkts; + s->total_bytes = total_bytes; +} + static clib_error_t * snat_config (vlib_main_t * vm, unformat_input_t * input) { @@ -3065,6 +3624,8 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) sm->icmp_match_in2out_cb = icmp_match_in2out_ed; sm->icmp_match_out2in_cb = icmp_match_out2in_ed; nat_affinity_init (vm); + nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb, + nat_ha_sref_ed_cb); } else { @@ -3075,6 +3636,7 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) sm->out2in_node_index = snat_out2in_node.index; sm->icmp_match_in2out_cb = icmp_match_in2out_slow; sm->icmp_match_out2in_cb = icmp_match_out2in_slow; + nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb); } if (!static_mapping_only || (static_mapping_only && static_mapping_connection_tracking)) @@ -3395,7 +3957,7 @@ nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port, return VNET_API_ERROR_UNSPECIFIED; s = pool_elt_at_index (tsm->sessions, value.value); - nat_free_session_data (sm, s, tsm - sm->per_thread_data); + nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); nat44_delete_session (sm, s, tsm - sm->per_thread_data); return 0; } @@ -3442,7 +4004,7 @@ nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port, if (pool_is_free_index (tsm->sessions, value.value)) return VNET_API_ERROR_UNSPECIFIED; s = pool_elt_at_index (tsm->sessions, value.value); - nat_free_session_data (sm, s, tsm - sm->per_thread_data); + nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0); nat44_delete_session (sm, s, tsm - sm->per_thread_data); return 0; }