X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fnat.c;h=5953c42f0fdb2c044795ed6994a4912753f3eff0;hb=f4fd0d4217ab6c41fe6b093871bd40ac130e6486;hp=9a620472b863023fc5dbd498c696c392314f1643;hpb=36a62702c5454d0a3f7e7aafc5b95d6ca0a7d703;p=vpp.git diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c old mode 100644 new mode 100755 index 9a620472b86..5953c42f0fd --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,8 @@ VNET_FEATURE_INIT (ip4_snat_in2out, static) = { VNET_FEATURE_INIT (ip4_snat_out2in, static) = { .arc_name = "ip4-unicast", .node_name = "nat44-out2in", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"), + .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa", + "ip4-dhcp-client-detect"), }; VNET_FEATURE_INIT (ip4_nat_classify, static) = { .arc_name = "ip4-unicast", @@ -152,6 +154,21 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data, thread_index); + if (is_fwd_bypass_session (s)) + { + ed_key.l_addr = s->in2out.addr; + ed_key.r_addr = s->ext_host_addr; + ed_key.l_port = s->in2out.port; + ed_key.r_port = s->ext_host_port; + ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol); + ed_key.fib_index = 0; + ed_kv.key[0] = ed_key.as_u64[0]; + ed_kv.key[1] = ed_key.as_u64[1]; + if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0)) + nat_log_warn ("in2out_ed key del failed"); + return; + } + /* Endpoint dependent session lookup tables */ if (is_ed_session (s)) { @@ -173,7 +190,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) ed_kv.key[0] = ed_key.as_u64[0]; ed_kv.key[1] = ed_key.as_u64[1]; if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0)) - clib_warning ("out2in_ed key del failed"); + nat_log_warn ("out2in_ed key del failed"); ed_key.l_addr = s->in2out.addr; ed_key.fib_index = s->in2out.fib_index; @@ -187,7 +204,7 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) ed_kv.key[0] = ed_key.as_u64[0]; ed_kv.key[1] = ed_key.as_u64[1]; if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0)) - clib_warning ("in2out_ed key del failed"); + nat_log_warn ("in2out_ed key del failed"); } if (snat_is_unk_proto_session (s)) @@ -224,10 +241,10 @@ nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) /* Session lookup tables */ kv.key = s->in2out.as_u64; if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0)) - clib_warning ("in2out key del failed"); + nat_log_warn ("in2out key del failed"); kv.key = s->out2in.as_u64; if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0)) - clib_warning ("out2in key del failed"); + nat_log_warn ("out2in key del failed"); if (snat_is_session_static (s)) return; @@ -271,7 +288,7 @@ 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)) - clib_warning ("user_hash keay add failed"); + nat_log_warn ("user_hash keay add failed"); } else { @@ -314,10 +331,19 @@ nat_session_alloc_or_recycle (snat_main_t *sm, snat_user_t *u, u32 thread_index) /* Get the session */ s = pool_elt_at_index (tsm->sessions, session_index); nat_free_session_data (sm, s, thread_index); + if (snat_is_session_static(s)) + u->nstaticsessions--; + else + u->nsessions--; s->outside_address_index = ~0; s->flags = 0; s->total_bytes = 0; s->total_pkts = 0; + s->state = 0; + s->ext_host_addr.as_u32 = 0; + s->ext_host_port = 0; + s->ext_host_nat_addr.as_u32 = 0; + s->ext_host_nat_port = 0; } else { @@ -342,6 +368,24 @@ nat_session_alloc_or_recycle (snat_main_t *sm, snat_user_t *u, u32 thread_index) return s; } +typedef struct { + u8 next_in2out; +} nat44_classify_trace_t; + +static u8 * format_nat44_classify_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + nat44_classify_trace_t *t = va_arg (*args, nat44_classify_trace_t *); + char *next; + + next = t->next_in2out ? "nat44-in2out" : "nat44-out2in"; + + s = format (s, "nat44-classify: next %s", next); + + return s; +} + static inline uword nat44_classify_node_fn_inline (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -350,6 +394,7 @@ nat44_classify_node_fn_inline (vlib_main_t * vm, u32 n_left_from, * from, * to_next; nat44_classify_next_t next_index; snat_main_t *sm = &snat_main; + snat_static_mapping_t *m; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -401,7 +446,9 @@ nat44_classify_node_fn_inline (vlib_main_t * vm, kv0.key = m_key0.as_u64; if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0)) { - next0 = NAT44_CLASSIFY_NEXT_OUT2IN; + m = pool_elt_at_index (sm->static_mappings, value0.value); + if (m->local_addr.as_u32 != m->external_addr.as_u32) + next0 = NAT44_CLASSIFY_NEXT_OUT2IN; goto enqueue0; } udp_header_t * udp0 = ip4_next_header (ip0); @@ -409,10 +456,22 @@ nat44_classify_node_fn_inline (vlib_main_t * vm, m_key0.protocol = ip_proto_to_snat_proto (ip0->protocol); kv0.key = m_key0.as_u64; if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0)) - next0 = NAT44_CLASSIFY_NEXT_OUT2IN; + { + m = pool_elt_at_index (sm->static_mappings, value0.value); + if (m->local_addr.as_u32 != m->external_addr.as_u32) + next0 = NAT44_CLASSIFY_NEXT_OUT2IN; + } } enqueue0: + if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + nat44_classify_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_in2out = next0 == NAT44_CLASSIFY_NEXT_IN2OUT ? 1 : 0; + } + /* verify speculative enqueue, maybe switch current next frame */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, @@ -437,6 +496,7 @@ VLIB_REGISTER_NODE (nat44_classify_node) = { .function = nat44_classify_node_fn, .name = "nat44-classify", .vector_size = sizeof (u32), + .format_trace = format_nat44_classify_trace, .type = VLIB_NODE_TYPE_INTERNAL, .n_next_nodes = NAT44_CLASSIFY_N_NEXT, .next_nodes = { @@ -460,6 +520,7 @@ VLIB_REGISTER_NODE (nat44_det_classify_node) = { .function = nat44_det_classify_node_fn, .name = "nat44-det-classify", .vector_size = sizeof (u32), + .format_trace = format_nat44_classify_trace, .type = VLIB_NODE_TYPE_INTERNAL, .n_next_nodes = NAT44_CLASSIFY_N_NEXT, .next_nodes = { @@ -483,6 +544,7 @@ VLIB_REGISTER_NODE (nat44_handoff_classify_node) = { .function = nat44_handoff_classify_node_fn, .name = "nat44-handoff-classify", .vector_size = sizeof (u32), + .format_trace = format_nat44_classify_trace, .type = VLIB_NODE_TYPE_INTERNAL, .n_next_nodes = NAT44_CLASSIFY_N_NEXT, .next_nodes = { @@ -522,7 +584,7 @@ snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index, if (is_add) fib_table_entry_update_one_path(fib_index, &prefix, - FIB_SOURCE_PLUGIN_HI, + FIB_SOURCE_PLUGIN_LOW, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_EXCLUSIVE), @@ -536,7 +598,7 @@ snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index, else fib_table_entry_delete(fib_index, &prefix, - FIB_SOURCE_PLUGIN_HI); + FIB_SOURCE_PLUGIN_LOW); } void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id, @@ -562,7 +624,7 @@ void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id, if (vrf_id != ~0) ap->fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id, - FIB_SOURCE_PLUGIN_HI); + FIB_SOURCE_PLUGIN_LOW); else ap->fib_index = ~0; #define _(N, i, n, s) \ @@ -654,7 +716,11 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, * @param addr_only If 0 address port and pair mapping, otherwise address only. * @param sw_if_index External port instead of specific IP address. * @param is_add If 0 delete static mapping, otherwise add. - * @param twice_nat If 1 translate external host address and port. + * @param twice_nat If value is TWICE_NAT then translate external host address + * and port. + * If value is TWICE_NAT_SELF then translate external host + * address and port whenever external host address equals + * local address of internal host. * @param out2in_only If 1 rule match only out2in direction * @param tag - opaque string tag * @@ -663,7 +729,8 @@ snat_add_static_mapping_when_resolved (snat_main_t * sm, int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, u32 vrf_id, int addr_only, u32 sw_if_index, snat_protocol_t proto, int is_add, - u8 twice_nat, u8 out2in_only, u8 * tag) + twice_nat_type_t twice_nat, u8 out2in_only, + u8 * tag) { snat_main_t * sm = &snat_main; snat_static_mapping_t *m; @@ -682,24 +749,24 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, u32 ses_index; u64 user_index; snat_session_t * s; + snat_static_map_resolve_t *rp, *rp_match = 0; /* If the external address is a specific interface address */ if (sw_if_index != ~0) { ip4_address_t * first_int_addr; - snat_static_map_resolve_t *rp, *rp_match = 0; for (i = 0; i < vec_len (sm->to_resolve); i++) { rp = sm->to_resolve + i; - if (rp->sw_if_index != sw_if_index && - rp->l_addr.as_u32 != l_addr.as_u32 && - rp->vrf_id != vrf_id && rp->addr_only != addr_only) + if (rp->sw_if_index != sw_if_index || + rp->l_addr.as_u32 != l_addr.as_u32 || + rp->vrf_id != vrf_id || rp->addr_only != addr_only) continue; if (!addr_only) { - if (rp->l_port != l_port && rp->e_port != e_port && rp->proto != proto) + if (rp->l_port != l_port || rp->e_port != e_port || rp->proto != proto) continue; } @@ -822,7 +889,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, foreach_snat_protocol #undef _ default: - clib_warning("unknown_protocol"); + nat_log_info ("unknown protocol"); return VNET_API_ERROR_INVALID_VALUE_2; } break; @@ -830,7 +897,26 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, } /* External address must be allocated */ if (!a && (l_addr.as_u32 != e_addr.as_u32)) - return VNET_API_ERROR_NO_SUCH_ENTRY; + { + if (sw_if_index != ~0) + { + for (i = 0; i < vec_len (sm->to_resolve); i++) + { + rp = sm->to_resolve + i; + if (rp->addr_only) + continue; + if (rp->sw_if_index != sw_if_index && + rp->l_addr.as_u32 != l_addr.as_u32 && + rp->vrf_id != vrf_id && rp->l_port != l_port && + rp->e_port != e_port && rp->proto != proto) + continue; + + vec_del1 (sm->to_resolve, i); + break; + } + } + return VNET_API_ERROR_NO_SUCH_ENTRY; + } } pool_get (sm->static_mappings, m); @@ -871,11 +957,11 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1); if (twice_nat || out2in_only) { - m_key.port = clib_host_to_net_u16 (l_port); + m_key.port = clib_host_to_net_u16 (m->local_port); kv.key = m_key.as_u64; kv.value = ~0ULL; if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1)) - clib_warning ("in2out key add failed"); + nat_log_warn ("in2out key add failed"); } m_key.addr = m->external_addr; @@ -890,7 +976,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, kv.key = m_key.as_u64; kv.value = ~0ULL; if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1)) - clib_warning ("out2in key add failed"); + nat_log_warn ("out2in key add failed"); } /* Delete dynamic sessions matching local address (+ local port) */ @@ -919,18 +1005,11 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, if (snat_is_session_static (s)) continue; - if (!addr_only) - { - if ((s->out2in.addr.as_u32 != e_addr.as_u32) && - (clib_net_to_host_u16 (s->out2in.port) != e_port)) - continue; - } + if (!addr_only && (clib_net_to_host_u16 (s->in2out.port) != m->local_port)) + continue; nat_free_session_data (sm, s, tsm - sm->per_thread_data); - clib_dlist_remove (tsm->list_pool, s->per_user_index); - pool_put_index (tsm->list_pool, s->per_user_index); - pool_put (tsm->sessions, s); - u->nsessions--; + nat44_delete_session (sm, s, tsm - sm->per_thread_data); if (!addr_only) break; @@ -942,7 +1021,12 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, else { if (!m) - return VNET_API_ERROR_NO_SUCH_ENTRY; + { + if (sw_if_index != ~0) + return 0; + else + return VNET_API_ERROR_NO_SUCH_ENTRY; + } /* Free external address port */ if (!(addr_only || sm->static_mapping_only || out2in_only)) @@ -966,7 +1050,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, foreach_snat_protocol #undef _ default: - clib_warning("unknown_protocol"); + nat_log_info ("unknown protocol"); return VNET_API_ERROR_INVALID_VALUE_2; } break; @@ -992,7 +1076,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, kv.key = m_key.as_u64; kv.value = ~0ULL; if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0)) - clib_warning ("in2out key del failed"); + nat_log_warn ("in2out key del failed"); } m_key.addr = m->external_addr; @@ -1006,7 +1090,7 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, kv.key = m_key.as_u64; kv.value = ~0ULL; if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0)) - clib_warning ("in2out key del failed"); + nat_log_warn ("out2in key del failed"); } /* Delete session(s) for static mapping if exist */ @@ -1040,16 +1124,19 @@ int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, continue; } + if (is_lb_session (s)) + continue; + + if (!snat_is_session_static (s)) + continue; + nat_free_session_data (sm, s, tsm - sm->per_thread_data); - clib_dlist_remove (tsm->list_pool, s->per_user_index); - pool_put_index (tsm->list_pool, s->per_user_index); - pool_put (tsm->sessions, s); - u->nstaticsessions--; + nat44_delete_session (sm, s, tsm - sm->per_thread_data); if (!addr_only) break; } - if (addr_only) + if (addr_only && (u->nstaticsessions == 0) && (u->nsessions == 0)) { pool_put (tsm->users, u); clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0); @@ -1117,7 +1204,8 @@ static int lb_local_exists (nat44_lb_addr_port_t * local, int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, snat_protocol_t proto, u32 vrf_id, nat44_lb_addr_port_t *locals, u8 is_add, - u8 twice_nat, u8 out2in_only, u8 *tag) + twice_nat_type_t twice_nat, u8 out2in_only, + u8 *tag) { snat_main_t * sm = &snat_main; snat_static_mapping_t *m; @@ -1154,7 +1242,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id, - FIB_SOURCE_PLUGIN_HI); + FIB_SOURCE_PLUGIN_LOW); /* Find external address in allocated addresses and reserve port for address and port pair mapping when dynamic translations enabled */ @@ -1182,7 +1270,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, foreach_snat_protocol #undef _ default: - clib_warning("unknown_protocol"); + nat_log_info ("unknown protocol"); return VNET_API_ERROR_INVALID_VALUE_2; } break; @@ -1213,7 +1301,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, kv.value = m - sm->static_mappings; if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1)) { - clib_warning ("static_mapping_by_external key add failed"); + nat_log_err ("static_mapping_by_external key add failed"); return VNET_API_ERROR_UNSPECIFIED; } @@ -1233,7 +1321,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, kv.value = ~0ULL; if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1)) { - clib_warning ("out2in key add failed"); + nat_log_err ("out2in key add failed"); return VNET_API_ERROR_UNSPECIFIED; } @@ -1257,7 +1345,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, kv.value = ~0ULL; if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1)) { - clib_warning ("in2out key add failed"); + nat_log_err ("in2out key add failed"); return VNET_API_ERROR_UNSPECIFIED; } } @@ -1267,7 +1355,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, if (!m) return VNET_API_ERROR_NO_SUCH_ENTRY; - fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_HI); + fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW); /* Free external address port */ if (!(sm->static_mapping_only || out2in_only)) @@ -1291,7 +1379,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, foreach_snat_protocol #undef _ default: - clib_warning("unknown_protocol"); + nat_log_info ("unknown protocol"); return VNET_API_ERROR_INVALID_VALUE_2; } break; @@ -1307,7 +1395,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, kv.key = m_key.as_u64; if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0)) { - clib_warning ("static_mapping_by_external key del failed"); + nat_log_err ("static_mapping_by_external key del failed"); return VNET_API_ERROR_UNSPECIFIED; } @@ -1315,7 +1403,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, kv.key = m_key.as_u64; if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0)) { - clib_warning ("outi2in key del failed"); + nat_log_err ("outi2in key del failed"); return VNET_API_ERROR_UNSPECIFIED; } @@ -1329,7 +1417,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, kv.key = m_key.as_u64; if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0)) { - clib_warning ("static_mapping_by_local key del failed"); + nat_log_err ("static_mapping_by_local key del failed"); return VNET_API_ERROR_UNSPECIFIED; } } @@ -1340,7 +1428,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, kv.key = m_key.as_u64; if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0)) { - clib_warning ("in2out key del failed"); + nat_log_err ("in2out key del failed"); return VNET_API_ERROR_UNSPECIFIED; } } @@ -1364,15 +1452,15 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, elt = pool_elt_at_index (tsm->list_pool, elt->next); ses_index = elt->value; + if (!(is_lb_session (s))) + continue; + if ((s->in2out.addr.as_u32 != local->addr.as_u32) && (clib_net_to_host_u16 (s->in2out.port) != local->port)) continue; nat_free_session_data (sm, s, tsm - sm->per_thread_data); - clib_dlist_remove (tsm->list_pool, s->per_user_index); - pool_put_index (tsm->list_pool, s->per_user_index); - pool_put (tsm->sessions, s); - u->nstaticsessions--; + nat44_delete_session (sm, s, tsm - sm->per_thread_data); } } } @@ -1393,9 +1481,6 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm, snat_address_t *a = 0; snat_session_t *ses; u32 *ses_to_be_removed = 0, *ses_index; - clib_bihash_kv_8_8_t kv, value; - snat_user_key_t user_key; - snat_user_t *u; snat_main_per_thread_data_t *tsm; snat_static_mapping_t *m; snat_interface_t *interface; @@ -1431,14 +1516,14 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm, /* Check if address is used in some static mapping */ if (is_snat_address_used_in_static_mapping(sm, addr)) { - clib_warning ("address used in static mapping"); + nat_log_notice ("address used in static mapping"); return VNET_API_ERROR_UNSPECIFIED; } } if (a->fib_index != ~0) fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4, - FIB_SOURCE_PLUGIN_HI); + FIB_SOURCE_PLUGIN_LOW); /* Delete sessions using address */ if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports) @@ -1450,22 +1535,15 @@ snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm, { ses->outside_address_index = ~0; nat_free_session_data (sm, ses, tsm - sm->per_thread_data); - clib_dlist_remove (tsm->list_pool, ses->per_user_index); - pool_put_index (tsm->list_pool, ses->per_user_index); vec_add1 (ses_to_be_removed, ses - tsm->sessions); - user_key.addr = ses->in2out.addr; - user_key.fib_index = ses->in2out.fib_index; - kv.key = user_key.as_u64; - if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) - { - u = pool_elt_at_index (tsm->users, value.value); - u->nsessions--; - } } })); vec_foreach (ses_index, ses_to_be_removed) - pool_put_index (tsm->sessions, ses_index[0]); + { + ses = pool_elt_at_index (tsm->sessions, ses_index[0]); + nat44_delete_session (sm, ses, tsm - sm->per_thread_data); + } vec_free (ses_to_be_removed); } @@ -1531,10 +1609,12 @@ int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) } if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1) - sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0); + sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, + NAT_FQ_NELTS); if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1) - sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0); + sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, + NAT_FQ_NELTS); pool_foreach (i, sm->interfaces, ({ @@ -1571,12 +1651,18 @@ int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) sw_if_index, 0, 0, 0); vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0); + if (!is_inside) + vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning", + sw_if_index, 1, 0, 0); } else { vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 0, 0, 0); pool_put (sm->interfaces, i); + if (is_inside) + vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning", + sw_if_index, 0, 0, 0); } } else @@ -1607,6 +1693,9 @@ int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) sw_if_index, 0, 0, 0); vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0); + if (!is_inside) + vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning", + sw_if_index, 0, 0, 0); goto set_flags; } @@ -1622,21 +1711,21 @@ int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) i->flags = 0; vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0); + if (is_inside && !sm->out2in_dpo) + vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning", + sw_if_index, 1, 0, 0); + set_flags: if (is_inside) - i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE; + { + i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE; + return 0; + } else i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE; /* Add/delete external addresses to FIB */ fib: - if (is_inside && !sm->out2in_dpo) - { - vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning", - sw_if_index, !is_del, 0, 0); - return 0; - } - vec_foreach (ap, sm->addresses) snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del); @@ -1742,7 +1831,7 @@ fib: pool_foreach (m, sm->static_mappings, ({ - if (!(m->addr_only)) + if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32)) continue; snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del); @@ -1816,6 +1905,7 @@ static clib_error_t * 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; sm->vlib_main = vm; sm->vnet_main = vnet_get_main(); @@ -1836,6 +1926,9 @@ static clib_error_t * snat_init (vlib_main_t * vm) sm->icmp_timeout = SNAT_ICMP_TIMEOUT; sm->alloc_addr_and_port = nat_alloc_addr_and_port_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; p = hash_get_mem (tm->thread_registrations_by_name, "workers"); if (p) @@ -1924,7 +2017,7 @@ void snat_free_outside_address_and_port (snat_address_t * addresses, foreach_snat_protocol #undef _ default: - clib_warning("unknown_protocol"); + nat_log_info ("unknown protocol"); return; } } @@ -1939,6 +2032,7 @@ void snat_free_outside_address_and_port (snat_address_t * addresses, * address. * @param is_addr_only If matched mapping is address only * @param twice_nat If matched mapping is twice NAT. + * @param lb If matched mapping is load-balanced. * * @returns 0 if match found otherwise 1. */ @@ -1947,7 +2041,8 @@ int snat_static_mapping_match (snat_main_t * sm, snat_session_key_t * mapping, u8 by_external, u8 *is_addr_only, - u8 *twice_nat) + twice_nat_type_t *twice_nat, + u8 *lb) { clib_bihash_kv_8_8_t kv, value; snat_static_mapping_t *m; @@ -2018,6 +2113,9 @@ int snat_static_mapping_match (snat_main_t * sm, if (PREDICT_FALSE(twice_nat != 0)) *twice_nat = m->twice_nat; + if (PREDICT_FALSE(lb != 0)) + *lb = vec_len (m->locals) > 0; + return 0; } @@ -2095,7 +2193,7 @@ nat_alloc_addr_and_port_default (snat_address_t * addresses, foreach_snat_protocol #undef _ default: - clib_warning("unknown protocol"); + nat_log_info ("unknown protocol"); return 1; } @@ -2127,7 +2225,7 @@ nat_alloc_addr_and_port_default (snat_address_t * addresses, foreach_snat_protocol #undef _ default: - clib_warning ("unknown protocol"); + nat_log_info ("unknown protocol"); return 1; } } @@ -2180,7 +2278,7 @@ nat_alloc_addr_and_port_mape (snat_address_t * addresses, foreach_snat_protocol #undef _ default: - clib_warning("unknown protocol"); + nat_log_info ("unknown protocol"); return 1; } @@ -2246,6 +2344,65 @@ format_snat_protocol (u8 * s, va_list * args) return s; } +u8 * format_snat_key (u8 * s, va_list * args); + +u8 * +format_session_kvp (u8 * s, va_list * args) +{ + clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *); + snat_session_key_t k; + + k.as_u64 = v->key; + + s = format (s, "%U session-index %llu", format_snat_key, &k, v->value); + + return s; +} + +u8 * +format_static_mapping_kvp (u8 * s, va_list * args) +{ + clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *); + snat_session_key_t k; + + k.as_u64 = v->key; + + s = format (s, "%U static-mapping-index %llu", format_snat_key, &k, v->value); + + return s; +} + +u8 * +format_user_kvp (u8 * s, va_list * args) +{ + clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *); + snat_user_key_t k; + + k.as_u64 = v->key; + + s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr, + k.fib_index, v->value); + + return s; +} + +u8 * +format_ed_session_kvp (u8 * s, va_list * args) +{ + clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *); + nat_ed_ses_key_t k; + + k.as_u64[0] = v->key[0]; + k.as_u64[1] = v->key[1]; + + s = format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu", + format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port), + format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port), + format_ip_protocol, k.proto, k.fib_index, v->value); + + return s; +} + static u32 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0) { @@ -2406,12 +2563,14 @@ static clib_error_t * snat_config (vlib_main_t * vm, unformat_input_t * input) { snat_main_t * sm = &snat_main; + nat66_main_t * nm = &nat66_main; u32 translation_buckets = 1024; u32 translation_memory_size = 128<<20; u32 user_buckets = 128; u32 user_memory_size = 64<<20; u32 max_translations_per_user = 100; u32 outside_vrf_id = 0; + u32 outside_ip6_vrf_id = 0; u32 inside_vrf_id = 0; u32 static_mapping_buckets = 1024; u32 static_mapping_memory_size = 64<<20; @@ -2444,6 +2603,9 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) else if (unformat (input, "outside VRF id %d", &outside_vrf_id)) ; + else if (unformat (input, "outside ip6 VRF id %d", + &outside_ip6_vrf_id)) + ; else if (unformat (input, "inside VRF id %d", &inside_vrf_id)) ; @@ -2487,6 +2649,10 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, outside_vrf_id, FIB_SOURCE_PLUGIN_HI); + nm->outside_vrf_id = outside_ip6_vrf_id; + nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, + outside_ip6_vrf_id, + FIB_SOURCE_PLUGIN_HI); sm->inside_vrf_id = inside_vrf_id; sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, inside_vrf_id, @@ -2522,19 +2688,29 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) { clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets, translation_memory_size); + clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out, + format_session_kvp); clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets, translation_memory_size); + clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in, + format_session_kvp); clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets, user_memory_size); + clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, + format_user_kvp); } clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed", translation_buckets, translation_memory_size); + clib_bihash_set_kvp_format_fn_16_8 (&sm->in2out_ed, + format_ed_session_kvp); clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed", translation_buckets, translation_memory_size); + clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed, + format_ed_session_kvp); } else { @@ -2544,10 +2720,14 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) clib_bihash_init_8_8 (&sm->static_mapping_by_local, "static_mapping_by_local", static_mapping_buckets, static_mapping_memory_size); + clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local, + format_static_mapping_kvp); clib_bihash_init_8_8 (&sm->static_mapping_by_external, "static_mapping_by_external", static_mapping_buckets, static_mapping_memory_size); + clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external, + format_static_mapping_kvp); } return 0; @@ -2585,7 +2765,7 @@ u8 * format_snat_key (u8 * s, va_list * args) u8 * format_snat_session (u8 * s, va_list * args) { - snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *); + snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *); snat_session_t * sess = va_arg (*args, snat_session_t *); if (snat_is_unk_proto_session (sess)) @@ -2604,20 +2784,25 @@ u8 * format_snat_session (u8 * s, va_list * args) s = format (s, " i2o %U\n", format_snat_key, &sess->in2out); s = format (s, " o2i %U\n", format_snat_key, &sess->out2in); } - if (is_twice_nat_session (sess)) - { - s = format (s, " external host o2i %U:%d i2o %U:%d\n", - format_ip4_address, &sess->ext_host_addr, - clib_net_to_host_u16 (sess->ext_host_port), - format_ip4_address, &sess->ext_host_nat_addr, - clib_net_to_host_u16 (sess->ext_host_nat_port)); - } - else + if (is_ed_session (sess) || is_fwd_bypass_session (sess)) { - if (sess->ext_host_addr.as_u32) - s = format (s, " external host %U\n", - format_ip4_address, &sess->ext_host_addr); + if (is_twice_nat_session (sess)) + { + s = format (s, " external host o2i %U:%d i2o %U:%d\n", + format_ip4_address, &sess->ext_host_addr, + clib_net_to_host_u16 (sess->ext_host_port), + format_ip4_address, &sess->ext_host_nat_addr, + clib_net_to_host_u16 (sess->ext_host_nat_port)); + } + else + { + if (sess->ext_host_addr.as_u32) + s = format (s, " external host %U:%u\n", + format_ip4_address, &sess->ext_host_addr, + clib_net_to_host_u16 (sess->ext_host_port)); + } } + s = format (s, " index %llu\n", sess - sm->sessions); s = format (s, " last heard %.2f\n", sess->last_heard); s = format (s, " total pkts %d, total bytes %lld\n", sess->total_pkts, sess->total_bytes); @@ -2625,7 +2810,9 @@ u8 * format_snat_session (u8 * s, va_list * args) s = format (s, " static translation\n"); else s = format (s, " dynamic translation\n"); - if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING) + if (is_fwd_bypass_session (sess)) + s = format (s, " forwarding-bypass\n"); + if (is_lb_session (sess)) s = format (s, " load-balancing\n"); if (is_twice_nat_session (sess)) s = format (s, " twice-nat\n"); @@ -2679,10 +2866,13 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args) nat44_lb_addr_port_t *local; if (m->addr_only) - s = format (s, "local %U external %U vrf %d %s", + s = format (s, "local %U external %U vrf %d %s %s", format_ip4_address, &m->local_addr, format_ip4_address, &m->external_addr, - m->vrf_id, m->twice_nat ? "twice-nat" : ""); + m->vrf_id, + m->twice_nat == TWICE_NAT ? "twice-nat" : + m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "", + m->out2in_only ? "out2in-only" : ""); else { if (vec_len (m->locals)) @@ -2691,7 +2881,8 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args) format_snat_protocol, m->proto, m->vrf_id, format_ip4_address, &m->external_addr, m->external_port, - m->twice_nat ? "twice-nat" : "", + m->twice_nat == TWICE_NAT ? "twice-nat" : + m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "", m->out2in_only ? "out2in-only" : ""); vec_foreach (local, m->locals) s = format (s, "\n local %U:%d probability %d\%", @@ -2703,7 +2894,9 @@ u8 * format_snat_static_mapping (u8 * s, va_list * args) format_snat_protocol, m->proto, format_ip4_address, &m->local_addr, m->local_port, format_ip4_address, &m->external_addr, m->external_port, - m->vrf_id, m->twice_nat ? "twice-nat" : "", + m->vrf_id, + m->twice_nat == TWICE_NAT ? "twice-nat" : + m->twice_nat == TWICE_NAT_SELF ? "self-twice-nat" : "", m->out2in_only ? "out2in-only" : ""); } return s; @@ -2826,7 +3019,7 @@ match: !is_delete, 0, 0, rp->tag); if (rv) - clib_warning ("snat_add_static_mapping returned %d", rv); + nat_log_notice ("snat_add_static_mapping returned %d", rv); } static void @@ -2897,8 +3090,7 @@ match: rp->is_add, 0, 0, rp->tag); if (rv) - clib_warning ("snat_add_static_mapping returned %d", - rv); + nat_log_notice ("snat_add_static_mapping returned %d", rv); } } return; @@ -2988,8 +3180,6 @@ nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, snat_session_key_t key; snat_session_t *s; clib_bihash_8_8_t *t; - snat_user_key_t u_key; - snat_user_t *u; ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32; if (sm->num_workers > 1) @@ -3007,27 +3197,57 @@ nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, t = is_in ? &tsm->in2out : &tsm->out2in; if (!clib_bihash_search_8_8 (t, &kv, &value)) { + if (pool_is_free_index (tsm->sessions, value.value)) + return VNET_API_ERROR_UNSPECIFIED; + s = pool_elt_at_index (tsm->sessions, value.value); - kv.key = s->in2out.as_u64; - clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0); - kv.key = s->out2in.as_u64; - clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0); - u_key.addr = s->in2out.addr; - u_key.fib_index = s->in2out.fib_index; - kv.key = u_key.as_u64; - if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) - { - u = pool_elt_at_index (tsm->users, value.value); - u->nsessions--; - } - clib_dlist_remove (tsm->list_pool, s->per_user_index); - pool_put (tsm->sessions, s); + nat_free_session_data (sm, s, tsm - sm->per_thread_data); + nat44_delete_session (sm, s, tsm - sm->per_thread_data); return 0; } return VNET_API_ERROR_NO_SUCH_ENTRY; } +int +nat44_del_ed_session (snat_main_t *sm, ip4_address_t *addr, u16 port, + ip4_address_t *eh_addr, u16 eh_port, u8 proto, + u32 vrf_id, int is_in) +{ + ip4_header_t ip; + clib_bihash_16_8_t *t; + nat_ed_ses_key_t key; + clib_bihash_kv_16_8_t kv, value; + u32 thread_index; + u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id); + snat_session_t *s; + + ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32; + if (sm->num_workers > 1) + thread_index = sm->worker_in2out_cb (&ip, fib_index); + else + thread_index = sm->num_workers; + + t = is_in ? &sm->in2out_ed : &sm->out2in_ed; + key.l_addr.as_u32 = addr->as_u32; + key.r_addr.as_u32 = eh_addr->as_u32; + key.l_port = clib_host_to_net_u16 (port); + key.r_port = clib_host_to_net_u16 (eh_port); + key.proto = proto; + key.fib_index = clib_host_to_net_u32 (fib_index); + kv.key[0] = key.as_u64[0]; + kv.key[1] = key.as_u64[1]; + if (clib_bihash_search_16_8 (t, &kv, &value)) + return VNET_API_ERROR_NO_SUCH_ENTRY; + + if (pool_is_free_index (sm->per_thread_data[thread_index].sessions, value.value)) + return VNET_API_ERROR_UNSPECIFIED; + s = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value.value); + nat_free_session_data (sm, s, thread_index); + nat44_delete_session (sm, s, thread_index); + return 0; +} + void nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length) {