X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fnat.c;h=c3583cabc218ac8b730f58e732614792e1f35d23;hb=df865200c769e31b5fe8f4b246516f07b80f4004;hp=ff3b2ed8a5f839e2b3c1d1a1b6e43398ff0460af;hpb=762a4938900abeedd42676ab2582fcceabdc07fa;p=vpp.git diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index ff3b2ed8a5f..c3583cabc21 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -211,6 +212,9 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) /* session lookup tables */ if (is_ed_session (s)) { + if (is_affinity_sessions (s)) + nat_affinity_unlock (s->ext_host_addr, s->out2in.addr, + s->in2out.protocol, s->out2in.port); ed_key.l_addr = s->out2in.addr; ed_key.r_addr = s->ext_host_addr; ed_key.fib_index = s->out2in.fib_index; @@ -230,7 +234,6 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) ed_kv.key[1] = ed_key.as_u64[1]; if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0)) nat_log_warn ("out2in_ed key del failed"); - ed_key.l_addr = s->in2out.addr; ed_key.fib_index = s->in2out.fib_index; if (!snat_is_unk_proto_session (s)) @@ -319,8 +322,6 @@ nat_user_get_or_create (snat_main_t *sm, ip4_address_t *addr, u32 fib_index, /* add user */ if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1)) nat_log_warn ("user_hash keay add failed"); - - clib_warning("%U %d", format_ip4_address, addr, fib_index); } else { @@ -400,6 +401,41 @@ nat_session_alloc_or_recycle (snat_main_t *sm, snat_user_t *u, u32 thread_index) return s; } +snat_session_t * +nat_ed_session_alloc (snat_main_t *sm, snat_user_t *u, u32 thread_index) +{ + snat_session_t *s; + snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; + dlist_elt_t * per_user_translation_list_elt; + + if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user) + { + 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); + return 0; + } + + pool_get (tsm->sessions, s); + memset (s, 0, sizeof (*s)); + s->outside_address_index = ~0; + + /* Create list elts */ + pool_get (tsm->list_pool, per_user_translation_list_elt); + clib_dlist_init (tsm->list_pool, + per_user_translation_list_elt - tsm->list_pool); + + per_user_translation_list_elt->value = s - tsm->sessions; + s->per_user_index = per_user_translation_list_elt - tsm->list_pool; + s->per_user_list_head_index = u->sessions_per_user_list_head_index; + + clib_dlist_addtail (tsm->list_pool, + s->per_user_list_head_index, + per_user_translation_list_elt - tsm->list_pool); + + return s; +} + typedef struct { u8 next_in2out; } nat44_classify_trace_t; @@ -706,6 +742,7 @@ int snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id, #define _(N, i, n, s) \ clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \ ap->busy_##n##_ports = 0; \ + ap->busy_##n##_ports_per_thread = 0;\ vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0); foreach_snat_protocol #undef _ @@ -780,6 +817,17 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, rp->is_add = is_add; rp->tag = vec_dup (tag); } + +static u32 get_thread_idx_by_port(u16 e_port) +{ + snat_main_t * sm = &snat_main; + u32 thread_idx = sm->num_workers; + if (sm->num_workers > 1) + { + thread_idx = sm->first_worker_index + sm->workers[(e_port - 1024) / sm->port_per_thread]; + } + return thread_idx; +} /** * @brief Add static mapping. @@ -967,7 +1015,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, if (e_port > 1024) \ { \ a->busy_##n##_ports++; \ - a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \ + a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \ } \ break; foreach_snat_protocol @@ -1112,7 +1160,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, if (e_port > 1024) \ { \ a->busy_##n##_ports--; \ - a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \ + a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \ } \ break; foreach_snat_protocol @@ -1226,7 +1274,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, snat_protocol_t proto, nat44_lb_addr_port_t *locals, u8 is_add, twice_nat_type_t twice_nat, u8 out2in_only, - u8 *tag) + u8 *tag, u32 affinity) { snat_main_t * sm = &snat_main; snat_static_mapping_t *m; @@ -1284,7 +1332,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, if (e_port > 1024) \ { \ a->busy_##n##_ports++; \ - a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \ + a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \ } \ break; foreach_snat_protocol @@ -1310,6 +1358,13 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, m->proto = proto; m->twice_nat = twice_nat; m->out2in_only = out2in_only; + m->affinity = affinity; + + if (affinity) + m->affinity_per_service_list_head_index = + nat_affinity_get_per_service_list_head_index(); + else + m->affinity_per_service_list_head_index = ~0; m_key.addr = m->external_addr; m_key.port = m->external_port; @@ -1380,7 +1435,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, if (e_port > 1024) \ { \ a->busy_##n##_ports--; \ - a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \ + a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \ } \ break; foreach_snat_protocol @@ -1466,6 +1521,8 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, } } } + if (m->affinity) + nat_affinity_flush_service (m->affinity_per_service_list_head_index); vec_free(m->locals); vec_free(m->tag); vec_free(m->workers); @@ -1551,6 +1608,12 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm, } } +#define _(N, i, n, s) \ + clib_bitmap_free (a->busy_##n##_port_bitmap); \ + vec_free (a->busy_##n##_ports_per_thread); + foreach_snat_protocol +#undef _ + if (twice_nat) { vec_del1 (sm->twice_nat_addresses, i); @@ -2017,10 +2080,12 @@ static clib_error_t * snat_init (vlib_main_t * vm) sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT; sm->icmp_timeout = SNAT_ICMP_TIMEOUT; sm->alloc_addr_and_port = nat_alloc_addr_and_port_default; + 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; p = hash_get_mem (tm->thread_registrations_by_name, "workers"); if (p) @@ -2140,13 +2205,15 @@ int snat_static_mapping_match (snat_main_t * sm, u8 by_external, u8 *is_addr_only, twice_nat_type_t *twice_nat, - u8 *lb) + lb_nat_type_t *lb, + ip4_address_t * ext_host_addr) { clib_bihash_kv_8_8_t kv, value; snat_static_mapping_t *m; snat_session_key_t m_key; clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local; u32 rand, lo = 0, hi, mid; + u8 backend_index; m_key.fib_index = match.fib_index; if (by_external) @@ -2177,6 +2244,19 @@ int snat_static_mapping_match (snat_main_t * sm, { if (vec_len (m->locals)) { + if (PREDICT_FALSE(lb != 0)) + *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT; + if (m->affinity) + { + if (nat_affinity_find_and_lock (ext_host_addr[0], match.addr, + match.protocol, match.port, &backend_index)) + goto get_local; + + mapping->addr = m->locals[backend_index].addr; + mapping->port = clib_host_to_net_u16 (m->locals[backend_index].port); + mapping->fib_index = m->locals[backend_index].fib_index; + goto end; + } get_local: hi = vec_len (m->locals) - 1; rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix); @@ -2198,9 +2278,18 @@ get_local: mapping->addr = m->locals[lo].addr; mapping->port = clib_host_to_net_u16 (m->locals[lo].port); mapping->fib_index = m->locals[lo].fib_index; + if (m->affinity) + { + if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr, + match.protocol, match.port, lo, m->affinity, + m->affinity_per_service_list_head_index)) + nat_log_info ("create affinity record failed"); + } } else { + if (PREDICT_FALSE(lb != 0)) + *lb = NO_LB_NAT; mapping->fib_index = m->fib_index; mapping->addr = m->local_addr; /* Address only mapping doesn't change port */ @@ -2218,15 +2307,13 @@ get_local: mapping->fib_index = sm->outside_fib_index; } +end: if (PREDICT_FALSE(is_addr_only != 0)) *is_addr_only = m->addr_only; if (PREDICT_FALSE(twice_nat != 0)) *twice_nat = m->twice_nat; - if (PREDICT_FALSE(lb != 0)) - *lb = vec_len (m->locals) > 0; - return 0; } @@ -2399,6 +2486,57 @@ exhausted: return 1; } +static int +nat_alloc_addr_and_port_range (snat_address_t * addresses, + u32 fib_index, + u32 thread_index, + snat_session_key_t * k, + u32 * address_indexp, + u16 port_per_thread, + u32 snat_thread_index) +{ + snat_main_t *sm = &snat_main; + snat_address_t *a = addresses; + u16 portnum, ports; + + ports = sm->end_port - sm->start_port + 1; + + if (!vec_len (addresses)) + goto exhausted; + + switch (k->protocol) + { +#define _(N, i, n, s) \ + case SNAT_PROTOCOL_##N: \ + if (a->busy_##n##_ports < ports) \ + { \ + while (1) \ + { \ + portnum = snat_random_port(sm->start_port, sm->end_port); \ + if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \ + continue; \ + clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \ + a->busy_##n##_ports++; \ + k->addr = a->addr; \ + k->port = clib_host_to_net_u16 (portnum); \ + *address_indexp = i; \ + return 0; \ + } \ + } \ + break; + foreach_snat_protocol +#undef _ + default: + nat_log_info ("unknown protocol"); + return 1; + } + +exhausted: + /* Totally out of translations to use... */ + snat_ipfix_logging_addresses_exhausted(0); + return 1; +} + void nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add) { @@ -2455,7 +2593,27 @@ format_snat_protocol (u8 * s, va_list * args) return s; } +u8 * +format_nat_addr_and_port_alloc_alg (u8 * s, va_list * args) +{ + u32 i = va_arg (*args, u32); + u8 *t = 0; + + switch (i) + { +#define _(v, N, s) case NAT_ADDR_AND_PORT_ALLOC_ALG_##N: t = (u8 *) s; break; + foreach_nat_addr_and_port_alloc_alg +#undef _ + default: + s = format (s, "unknown"); + return s; + } + s = format (s, "%s", t); + return s; +} + u8 * format_snat_key (u8 * s, va_list * args); +u8 * format_static_mapping_key (u8 * s, va_list * args); u8 * format_session_kvp (u8 * s, va_list * args) @@ -2478,7 +2636,8 @@ format_static_mapping_kvp (u8 * s, va_list * args) k.as_u64 = v->key; - s = format (s, "%U static-mapping-index %llu", format_snat_key, &k, v->value); + s = format (s, "%U static-mapping-index %llu", + format_static_mapping_key, &k, v->value); return s; } @@ -2812,6 +2971,18 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) format_unformat_error, input); } + if (sm->deterministic && sm->endpoint_dependent) + return clib_error_return ( + 0, "deterministic and endpoint-dependent modes are mutually exclusive"); + + if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent)) + return clib_error_return ( + 0, "static mapping only mode available only for simple nat"); + + if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent)) + return clib_error_return ( + 0, "out2in dpo mode available only for simple nat"); + /* for show commands, etc. */ sm->translation_buckets = translation_buckets; sm->translation_memory_size = translation_memory_size; @@ -2857,6 +3028,7 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) sm->out2in_node_index = nat44_ed_out2in_node.index; sm->icmp_match_in2out_cb = icmp_match_in2out_ed; sm->icmp_match_out2in_cb = icmp_match_out2in_ed; + nat_affinity_init (vm); } else { @@ -2960,6 +3132,17 @@ u8 * format_snat_key (u8 * s, va_list * args) return s; } +u8 * format_static_mapping_key (u8 * s, va_list * args) +{ + snat_session_key_t * key = va_arg (*args, snat_session_key_t *); + + s = format (s, "%U proto %U port %d fib %d", + format_ip4_address, &key->addr, + format_snat_protocol, key->protocol, + key->port, key->fib_index); + return s; +} + u8 * format_snat_session (u8 * s, va_list * args) { snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *); @@ -3457,17 +3640,30 @@ nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length) { snat_main_t *sm = &snat_main; + sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE; sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape; sm->psid = psid; sm->psid_offset = psid_offset; sm->psid_length = psid_length; } +void +nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port) +{ + snat_main_t *sm = &snat_main; + + sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE; + sm->alloc_addr_and_port = nat_alloc_addr_and_port_range; + sm->start_port = start_port; + sm->end_port = end_port; +} + void nat_set_alloc_addr_and_port_default (void) { snat_main_t *sm = &snat_main; + sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT; sm->alloc_addr_and_port = nat_alloc_addr_and_port_default; }