From 229c1aaf7501afa95c3768702bb1e76beb59384c Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Mon, 28 May 2018 04:09:52 -0700 Subject: [PATCH] NAT44: code cleanup and refactor (VPP-1285) Change-Id: I088163f10ae5515d7a9115781cc13ef563fafed5 Signed-off-by: Matus Fabian --- src/plugins/nat/dslite_ce_decap.c | 1 + src/plugins/nat/dslite_ce_encap.c | 1 + src/plugins/nat/dslite_in2out.c | 1 + src/plugins/nat/dslite_out2in.c | 1 + src/plugins/nat/in2out.c | 167 +++++++++++---------- src/plugins/nat/nat.c | 235 ++++++++++++++++++----------- src/plugins/nat/nat.h | 207 +++----------------------- src/plugins/nat/nat44_cli.c | 7 +- src/plugins/nat/nat64.c | 1 + src/plugins/nat/nat64_cli.c | 1 + src/plugins/nat/nat64_db.c | 1 + src/plugins/nat/nat64_in2out.c | 1 + src/plugins/nat/nat64_out2in.c | 1 + src/plugins/nat/nat_api.c | 3 +- src/plugins/nat/nat_inlines.h | 250 +++++++++++++++++++++++++++++++ src/plugins/nat/nat_ipfix_logging.c | 1 + src/plugins/nat/out2in.c | 215 +++++++++++++-------------- test/test_nat.py | 286 +++++++++++++++++++----------------- 18 files changed, 781 insertions(+), 599 deletions(-) create mode 100644 src/plugins/nat/nat_inlines.h diff --git a/src/plugins/nat/dslite_ce_decap.c b/src/plugins/nat/dslite_ce_decap.c index 615a424e871..c16ac17c2a6 100644 --- a/src/plugins/nat/dslite_ce_decap.c +++ b/src/plugins/nat/dslite_ce_decap.c @@ -13,6 +13,7 @@ * limitations under the License. */ #include +#include vlib_node_registration_t dslite_ce_decap_node; diff --git a/src/plugins/nat/dslite_ce_encap.c b/src/plugins/nat/dslite_ce_encap.c index f098d75ca70..d83ca9c8046 100644 --- a/src/plugins/nat/dslite_ce_encap.c +++ b/src/plugins/nat/dslite_ce_encap.c @@ -13,6 +13,7 @@ * limitations under the License. */ #include +#include vlib_node_registration_t dslite_ce_encap_node; diff --git a/src/plugins/nat/dslite_in2out.c b/src/plugins/nat/dslite_in2out.c index 98b3a1618f7..ab0055cfee2 100644 --- a/src/plugins/nat/dslite_in2out.c +++ b/src/plugins/nat/dslite_in2out.c @@ -13,6 +13,7 @@ * limitations under the License. */ #include +#include vlib_node_registration_t dslite_in2out_node; vlib_node_registration_t dslite_in2out_slowpath_node; diff --git a/src/plugins/nat/dslite_out2in.c b/src/plugins/nat/dslite_out2in.c index 802b2a91544..6bfc6e979cd 100644 --- a/src/plugins/nat/dslite_out2in.c +++ b/src/plugins/nat/dslite_out2in.c @@ -13,6 +13,7 @@ * limitations under the License. */ #include +#include vlib_node_registration_t dslite_out2in_node; diff --git a/src/plugins/nat/in2out.c b/src/plugins/nat/in2out.c index 1659ed0fec3..c724553e36b 100755 --- a/src/plugins/nat/in2out.c +++ b/src/plugins/nat/in2out.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -127,7 +128,8 @@ _(NO_TRANSLATION, "No translation") \ _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \ _(DROP_FRAGMENT, "Drop fragment") \ _(MAX_REASS, "Maximum reassemblies exceeded") \ -_(MAX_FRAG, "Maximum fragments per reassembly exceeded") +_(MAX_FRAG, "Maximum fragments per reassembly exceeded")\ +_(FQ_CONGESTED, "Handoff frame queue congested") typedef enum { #define _(sym,str) SNAT_IN2OUT_ERROR_##sym, @@ -316,6 +318,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, { b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED]; nat_ipfix_logging_max_sessions(sm->max_translations); + nat_log_notice ("maximum sessions exceeded"); return SNAT_IN2OUT_NEXT_DROP; } @@ -333,7 +336,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, thread_index); if (!u) { - clib_warning ("create NAT user failed"); + nat_log_warn ("create NAT user failed"); return SNAT_IN2OUT_NEXT_DROP; } @@ -357,7 +360,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) { - clib_warning ("create NAT session failed"); + nat_log_warn ("create NAT session failed"); return SNAT_IN2OUT_NEXT_DROP; } @@ -378,14 +381,14 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, kv0.value = s - sm->per_thread_data[thread_index].sessions; if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0, 1 /* is_add */)) - clib_warning ("in2out key add failed"); + nat_log_notice ("in2out key add failed"); kv0.key = s->out2in.as_u64; kv0.value = s - sm->per_thread_data[thread_index].sessions; if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0, 1 /* is_add */)) - clib_warning ("out2in key add failed"); + nat_log_notice ("out2in key add failed"); /* log NAT event */ snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32, @@ -497,7 +500,6 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, clib_bihash_kv_16_8_t kv, value; udp_header_t *udp; snat_session_t *s = 0; - snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; f64 now = vlib_time_now (sm->vlib_main); if (!sm->forwarding_enabled) @@ -540,12 +542,9 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, return 1; } /* Per-user LRU list maintenance */ - clib_dlist_remove (tsm->list_pool, s->per_user_index); - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); + nat44_session_update_lru (sm, s, thread_index); /* Accounting */ - s->last_heard = now; - s->total_pkts++; + nat44_session_update_counters (s, now, 0); return 1; } else @@ -1083,15 +1082,10 @@ static inline u32 icmp_in2out_slow_path (snat_main_t *sm, if (vnet_buffer(b0)->sw_if_index[VLIB_TX] == 0) snat_icmp_hairpinning(sm, b0, ip0, icmp0); /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (sm->vlib_main, b0)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); + nat44_session_update_lru (sm, s0, thread_index); } return next0; } @@ -1198,6 +1192,7 @@ snat_in2out_unknown_proto (snat_main_t *sm, { b->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED]; nat_ipfix_logging_max_sessions(sm->max_translations); + nat_log_notice ("maximum sessions exceeded"); return 0; } @@ -1205,7 +1200,7 @@ snat_in2out_unknown_proto (snat_main_t *sm, thread_index); if (!u) { - clib_warning ("create NAT user failed"); + nat_log_warn ("create NAT user failed"); return 0; } @@ -1280,7 +1275,7 @@ create_ses: s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) { - clib_warning ("create NAT session failed"); + nat_log_warn ("create NAT session failed"); return 0; } @@ -1306,14 +1301,14 @@ create_ses: s_kv.key[1] = key.as_u64[1]; s_kv.value = s - tsm->sessions; if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1)) - clib_warning ("in2out key add failed"); + nat_log_notice ("in2out key add failed"); key.l_addr.as_u32 = new_addr; key.fib_index = sm->outside_fib_index; s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1)) - clib_warning ("out2in key add failed"); + nat_log_notice ("out2in key add failed"); } /* Update IP checksum */ @@ -1322,13 +1317,9 @@ create_ses: ip->checksum = ip_csum_fold (sum); /* Accounting */ - s->last_heard = now; - s->total_pkts++; - s->total_bytes += vlib_buffer_length_in_chain (vm, b); + nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b)); /* Per-user LRU list maintenance */ - clib_dlist_remove (tsm->list_pool, s->per_user_index); - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); + nat44_session_update_lru (sm, s, thread_index); /* Hairpinning */ if (vnet_buffer(b)->sw_if_index[VLIB_TX] == ~0) @@ -1386,9 +1377,7 @@ snat_in2out_lb (snat_main_t *sm, return 0; } /* Per-user LRU list maintenance */ - clib_dlist_remove (tsm->list_pool, s->per_user_index); - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); + nat44_session_update_lru (sm, s, thread_index); return 0; } } @@ -1398,6 +1387,7 @@ snat_in2out_lb (snat_main_t *sm, { b->error = node->errors[SNAT_IN2OUT_ERROR_MAX_SESSIONS_EXCEEDED]; nat_ipfix_logging_max_sessions(sm->max_translations); + nat_log_notice ("maximum sessions exceeded"); return 0; } @@ -1412,18 +1402,19 @@ snat_in2out_lb (snat_main_t *sm, thread_index); if (!u) { - clib_warning ("create NAT user failed"); + nat_log_warn ("create NAT user failed"); return 0; } s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) { - clib_warning ("create NAT session failed"); + nat_log_warn ("create NAT session failed"); return 0; } s->ext_host_addr.as_u32 = ip->dst_address.as_u32; + s->ext_host_port = udp->dst_port; s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; if (lb) s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING; @@ -1437,7 +1428,7 @@ snat_in2out_lb (snat_main_t *sm, /* Add to lookup tables */ s_kv.value = s - tsm->sessions; if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1)) - clib_warning ("in2out-ed key add failed"); + nat_log_notice ("in2out-ed key add failed"); key.l_addr = e_key.addr; key.fib_index = e_key.fib_index; @@ -1445,7 +1436,7 @@ snat_in2out_lb (snat_main_t *sm, s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1)) - clib_warning ("out2in-ed key add failed"); + nat_log_notice ("out2in-ed key add failed"); } new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32; @@ -1496,13 +1487,10 @@ snat_in2out_lb (snat_main_t *sm, } /* Accounting */ - s->last_heard = now; - s->total_pkts++; - s->total_bytes += vlib_buffer_length_in_chain (vm, b); + nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b)); /* Per-user LRU list maintenance */ - clib_dlist_remove (tsm->list_pool, s->per_user_index); - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); + nat44_session_update_lru (sm, s, thread_index); + return s; } @@ -1747,15 +1735,10 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (vm, b0)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); + nat44_session_update_lru (sm, s0, thread_index); trace00: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1939,15 +1922,10 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } /* Accounting */ - s1->last_heard = now; - s1->total_pkts++; - s1->total_bytes += vlib_buffer_length_in_chain (vm, b1); + nat44_session_update_counters (s1, now, + vlib_buffer_length_in_chain (vm, b1)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s1->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s1->per_user_list_head_index, - s1->per_user_index); + nat44_session_update_lru (sm, s1, thread_index); trace01: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -2168,15 +2146,10 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (vm, b0)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); + nat44_session_update_lru (sm, s0, thread_index); trace0: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -2614,6 +2587,7 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm, { next0 = SNAT_IN2OUT_NEXT_DROP; b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_REASS]; + nat_log_notice ("maximum reassemblies exceeded"); goto trace0; } @@ -2654,6 +2628,7 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm, if (nat_ip4_reass_add_fragment (reass0, bi0)) { b0->error = node->errors[SNAT_IN2OUT_ERROR_MAX_FRAG]; + nat_log_notice ("maximum fragments per reassembly exceeded"); next0 = SNAT_IN2OUT_NEXT_DROP; goto trace0; } @@ -2705,15 +2680,10 @@ nat44_in2out_reass_node_fn (vlib_main_t * vm, s0->ext_host_port, proto0); /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (vm, b0)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); + nat44_session_update_lru (sm, s0, thread_index); trace0: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -2907,8 +2877,8 @@ snat_det_in2out_node_fn (vlib_main_t * vm, dm0 = snat_det_map_by_user(sm, &ip0->src_address); if (PREDICT_FALSE(!dm0)) { - clib_warning("no match for internal host %U", - format_ip4_address, &ip0->src_address); + nat_log_info ("no match for internal host %U", + format_ip4_address, &ip0->src_address); next0 = SNAT_IN2OUT_NEXT_DROP; b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; goto trace0; @@ -3057,8 +3027,8 @@ snat_det_in2out_node_fn (vlib_main_t * vm, dm1 = snat_det_map_by_user(sm, &ip1->src_address); if (PREDICT_FALSE(!dm1)) { - clib_warning("no match for internal host %U", - format_ip4_address, &ip0->src_address); + nat_log_info ("no match for internal host %U", + format_ip4_address, &ip0->src_address); next1 = SNAT_IN2OUT_NEXT_DROP; b1->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; goto trace1; @@ -3243,8 +3213,8 @@ snat_det_in2out_node_fn (vlib_main_t * vm, dm0 = snat_det_map_by_user(sm, &ip0->src_address); if (PREDICT_FALSE(!dm0)) { - clib_warning("no match for internal host %U", - format_ip4_address, &ip0->src_address); + nat_log_info ("no match for internal host %U", + format_ip4_address, &ip0->src_address); next0 = SNAT_IN2OUT_NEXT_DROP; b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; goto trace00; @@ -3476,8 +3446,8 @@ u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node, dm0 = snat_det_map_by_user(sm, &in_addr); if (PREDICT_FALSE(!dm0)) { - clib_warning("no match for internal host %U", - format_ip4_address, &in_addr); + nat_log_info ("no match for internal host %U", + format_ip4_address, &in_addr); if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0, IP_PROTOCOL_ICMP, rx_fib_index0))) { @@ -3568,11 +3538,12 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm, { snat_main_t *sm = &snat_main; vlib_thread_main_t *tm = vlib_get_thread_main (); - u32 n_left_from, *from, *to_next = 0; + u32 n_left_from, *from, *to_next = 0, *to_next_drop = 0; static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index; static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index = 0; vlib_frame_queue_elt_t *hf = 0; + vlib_frame_queue_t *fq; vlib_frame_t *f = 0; int i; u32 n_left_to_next_worker = 0, *to_next_worker = 0; @@ -3581,6 +3552,7 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm, u32 thread_index = vlib_get_thread_index (); u32 fq_index; u32 to_node_index; + vlib_frame_t *d = 0; ASSERT (vec_len (sm->workers)); @@ -3600,7 +3572,7 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm, vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1); vec_validate_init_empty (congested_handoff_queue_by_worker_index, - sm->first_worker_index + sm->num_workers - 1, + tm->n_vlib_mains - 1, (vlib_frame_queue_t *) (~0)); } @@ -3635,6 +3607,26 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm, if (next_worker_index != current_worker_index) { + fq = is_vlib_frame_queue_congested ( + fq_index, next_worker_index, NAT_FQ_NELTS - 2, + congested_handoff_queue_by_worker_index); + + if (fq) + { + /* if this is 1st frame */ + if (!d) + { + d = vlib_get_frame_to_node (vm, sm->error_node_index); + to_next_drop = vlib_frame_vector_args (d); + } + + to_next_drop[0] = bi0; + to_next_drop += 1; + d->n_vectors++; + b0->error = node->errors[SNAT_IN2OUT_ERROR_FQ_CONGESTED]; + goto trace0; + } + if (hf) hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; @@ -3676,6 +3668,7 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm, f->n_vectors++; } +trace0: if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) { @@ -3689,6 +3682,9 @@ snat_in2out_worker_handoff_fn_inline (vlib_main_t * vm, if (f) vlib_put_frame_to_node (vm, to_node_index, f); + if (d) + vlib_put_frame_to_node (vm, sm->error_node_index, d); + if (hf) hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; @@ -3733,6 +3729,9 @@ VLIB_REGISTER_NODE (snat_in2out_worker_handoff_node) = { .format_trace = format_snat_in2out_worker_handoff_trace, .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(snat_in2out_error_strings), + .error_strings = snat_in2out_error_strings, + .n_next_nodes = 1, .next_nodes = { diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 8ebec585d8a..1d493a6d346 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -164,7 +165,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"); return; } @@ -189,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; @@ -203,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)) @@ -240,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; @@ -287,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 { @@ -367,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, @@ -445,6 +464,14 @@ nat44_classify_node_fn_inline (vlib_main_t * vm, } 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, @@ -469,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 = { @@ -492,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 = { @@ -515,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 = { @@ -859,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; @@ -931,7 +961,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, 1)) - clib_warning ("in2out key add failed"); + nat_log_warn ("in2out key add failed"); } m_key.addr = m->external_addr; @@ -946,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) */ @@ -979,10 +1009,7 @@ int 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); - 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; @@ -1023,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; @@ -1049,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; @@ -1063,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 ("out2in key del failed"); + nat_log_warn ("out2in key del failed"); } /* Delete session(s) for static mapping if exist */ @@ -1104,15 +1131,12 @@ int 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); - 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 && (u->nstaticsessions == 0)) + 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); @@ -1246,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; @@ -1277,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; } @@ -1297,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; } @@ -1321,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; } } @@ -1355,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; @@ -1371,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; } @@ -1379,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; } @@ -1393,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; } } @@ -1404,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; } } @@ -1436,10 +1460,7 @@ int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_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); } } } @@ -1460,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; @@ -1498,7 +1516,7 @@ 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; } } @@ -1517,25 +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); - if (snat_is_session_static (ses)) - u->nstaticsessions--; - else - 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); } @@ -1601,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, ({ @@ -1895,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(); @@ -1915,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) @@ -2003,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; } } @@ -2179,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; } @@ -2211,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; } } @@ -2264,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; } @@ -2330,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) { @@ -2615,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 { @@ -2637,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; @@ -2678,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)) @@ -2715,6 +2802,7 @@ u8 * format_snat_session (u8 * s, va_list * args) 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); @@ -2724,7 +2812,7 @@ u8 * format_snat_session (u8 * s, va_list * args) s = format (s, " dynamic translation\n"); if (is_fwd_bypass_session (sess)) s = format (s, " forwarding-bypass\n"); - if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING) + if (is_lb_session (sess)) s = format (s, " load-balancing\n"); if (is_twice_nat_session (sess)) s = format (s, " twice-nat\n"); @@ -2931,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 @@ -3002,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; @@ -3093,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) @@ -3116,24 +3201,8 @@ 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); - 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); - if (snat_is_session_static (s)) - u->nstaticsessions--; - else - u->nsessions--; - } - 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); + nat_free_session_data (sm, s, tsm - sm->per_thread_data); + nat44_delete_session (sm, s, tsm - sm->per_thread_data); return 0; } diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index f889976dd52..9de65d97e03 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -28,6 +28,7 @@ #include #include #include +#include #define SNAT_UDP_TIMEOUT 300 @@ -37,6 +38,8 @@ #define SNAT_TCP_INCOMING_SYN 6 #define SNAT_ICMP_TIMEOUT 60 +#define NAT_FQ_NELTS 64 + #define SNAT_FLAG_HAIRPINNING (1 << 0) /* Key */ @@ -131,7 +134,7 @@ typedef enum { #define NAT44_SES_I2O_FIN_ACK 4 #define NAT44_SES_O2I_FIN_ACK 8 -#define nat44_is_ses_closed(s) (s->state == 0xf) +#define nat44_is_ses_closed(s) s->state == 0xf #define SNAT_SESSION_FLAG_STATIC_MAPPING 1 #define SNAT_SESSION_FLAG_UNKNOWN_PROTO 2 @@ -370,6 +373,7 @@ typedef struct snat_main_s { u32 in2out_node_index; u32 in2out_output_node_index; u32 out2in_node_index; + u32 error_node_index; /* Deterministic NAT */ snat_det_map_t * det_maps; @@ -402,6 +406,9 @@ typedef struct snat_main_s { /* API message ID base */ u16 msg_id_base; + /* log class */ + vlib_log_class_t log_class; + /* convenience */ vlib_main_t * vlib_main; vnet_main_t * vnet_main; @@ -453,6 +460,7 @@ void snat_add_del_addr_to_fib (ip4_address_t * addr, format_function_t format_snat_user; format_function_t format_snat_static_mapping; format_function_t format_snat_static_map_to_resolve; +format_function_t format_snat_session; format_function_t format_det_map_ses; typedef struct { @@ -499,6 +507,17 @@ typedef struct { #define nat_interface_is_inside(i) i->flags & NAT_INTERFACE_FLAG_IS_INSIDE #define nat_interface_is_outside(i) i->flags & NAT_INTERFACE_FLAG_IS_OUTSIDE +#define nat_log_err(...) \ + vlib_log(VLIB_LOG_LEVEL_ERR, snat_main.log_class, __VA_ARGS__) +#define nat_log_warn(...) \ + vlib_log(VLIB_LOG_LEVEL_WARNING, snat_main.log_class, __VA_ARGS__) +#define nat_log_notice(...) \ + vlib_log(VLIB_LOG_LEVEL_NOTICE, snat_main.log_class, __VA_ARGS__) +#define nat_log_info(...) \ + vlib_log(VLIB_LOG_LEVEL_INFO, snat_main.log_class, __VA_ARGS__) +#define nat_log_debug(...)\ + vlib_log(VLIB_LOG_LEVEL_DEBUG, snat_main.log_class, __VA_ARGS__) + /* * Why is this here? Because we don't need to touch this layer to * simply reply to an icmp. We need to change id to a unique @@ -510,31 +529,6 @@ typedef struct { u16 sequence; } icmp_echo_header_t; -always_inline u32 -ip_proto_to_snat_proto (u8 ip_proto) -{ - u32 snat_proto = ~0; - - snat_proto = (ip_proto == IP_PROTOCOL_UDP) ? SNAT_PROTOCOL_UDP : snat_proto; - snat_proto = (ip_proto == IP_PROTOCOL_TCP) ? SNAT_PROTOCOL_TCP : snat_proto; - snat_proto = (ip_proto == IP_PROTOCOL_ICMP) ? SNAT_PROTOCOL_ICMP : snat_proto; - snat_proto = (ip_proto == IP_PROTOCOL_ICMP6) ? SNAT_PROTOCOL_ICMP : snat_proto; - - return snat_proto; -} - -always_inline u8 -snat_proto_to_ip_proto (snat_protocol_t snat_proto) -{ - u8 ip_proto = ~0; - - ip_proto = (snat_proto == SNAT_PROTOCOL_UDP) ? IP_PROTOCOL_UDP : ip_proto; - ip_proto = (snat_proto == SNAT_PROTOCOL_TCP) ? IP_PROTOCOL_TCP : ip_proto; - ip_proto = (snat_proto == SNAT_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP : ip_proto; - - return ip_proto; -} - typedef struct { u16 src_port, dst_port; } tcp_udp_header_t; @@ -609,165 +603,4 @@ void nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length); void nat_set_alloc_addr_and_port_default (void); -static_always_inline u8 -icmp_is_error_message (icmp46_header_t * icmp) -{ - switch(icmp->type) - { - case ICMP4_destination_unreachable: - case ICMP4_time_exceeded: - case ICMP4_parameter_problem: - case ICMP4_source_quench: - case ICMP4_redirect: - case ICMP4_alternate_host_address: - return 1; - } - return 0; -} - -static_always_inline u8 -is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, - u32 ip4_addr) -{ - snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data; - ip4_address_t * first_int_addr; - - if (PREDICT_FALSE(rt->cached_sw_if_index != sw_if_index0)) - { - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index0, - 0 /* just want the address */); - rt->cached_sw_if_index = sw_if_index0; - if (first_int_addr) - rt->cached_ip4_address = first_int_addr->as_u32; - else - rt->cached_ip4_address = 0; - } - - if (PREDICT_FALSE(ip4_addr == rt->cached_ip4_address)) - return 1; - else - return 0; -} - -always_inline u8 -maximum_sessions_exceeded (snat_main_t *sm, u32 thread_index) -{ - if (pool_elts (sm->per_thread_data[thread_index].sessions) >= sm->max_translations) - return 1; - - return 0; -} - -static_always_inline void -nat_send_all_to_node(vlib_main_t *vm, u32 *bi_vector, - vlib_node_runtime_t *node, vlib_error_t *error, u32 next) -{ - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - - from = bi_vector; - n_left_from = vec_len(bi_vector); - next_index = node->cached_next_index; - while (n_left_from > 0) { - vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next); - while (n_left_from > 0 && n_left_to_next > 0) { - u32 bi0 = to_next[0] = from[0]; - from += 1; - n_left_from -= 1; - to_next += 1; - n_left_to_next -= 1; - vlib_buffer_t *p0 = vlib_get_buffer(vm, bi0); - p0->error = *error; - vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, - n_left_to_next, bi0, next); - } - vlib_put_next_frame(vm, node, next_index, n_left_to_next); - } -} - -always_inline void -user_session_increment(snat_main_t *sm, snat_user_t *u, u8 is_static) -{ - if (u->nsessions + u->nstaticsessions < sm->max_translations_per_user) - { - if (is_static) - u->nstaticsessions++; - else - u->nsessions++; - } -} - -always_inline void -nat44_delete_session(snat_main_t * sm, snat_session_t * ses, u32 thread_index) -{ - snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data, - thread_index); - clib_bihash_kv_8_8_t kv, value; - snat_user_key_t u_key; - snat_user_t *u; - u_key.addr = ses->in2out.addr; - u_key.fib_index = ses->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); - if (snat_is_session_static(ses)) - u->nstaticsessions--; - else - u->nsessions--; - } - clib_dlist_remove (tsm->list_pool, ses->per_user_index); - pool_put_index (tsm->list_pool, ses->per_user_index); - pool_put (tsm->sessions, ses); -} - -/** \brief Set TCP session state. - @return 1 if session was closed, otherwise 0 -*/ -always_inline int -nat44_set_tcp_session_state_i2o(snat_main_t * sm, snat_session_t * ses, - tcp_header_t * tcp, u32 thread_index) -{ - if (tcp->flags & TCP_FLAG_FIN) - { - ses->i2o_fin_seq = clib_net_to_host_u32 (tcp->seq_number); - ses->state |= NAT44_SES_I2O_FIN; - } - if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN)) - { - if (clib_net_to_host_u32 (tcp->ack_number) > ses->o2i_fin_seq) - ses->state |= NAT44_SES_O2I_FIN_ACK; - } - if (nat44_is_ses_closed (ses)) - { - nat_free_session_data (sm, ses, thread_index); - nat44_delete_session (sm, ses, thread_index); - return 1; - } - return 0; -} - -always_inline int -nat44_set_tcp_session_state_o2i(snat_main_t * sm, snat_session_t * ses, - tcp_header_t * tcp, u32 thread_index) -{ - if (tcp->flags & TCP_FLAG_FIN) - { - ses->o2i_fin_seq = clib_net_to_host_u32 (tcp->seq_number); - ses->state |= NAT44_SES_O2I_FIN; - } - if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_FIN)) - { - if (clib_net_to_host_u32 (tcp->ack_number) > ses->i2o_fin_seq) - ses->state |= NAT44_SES_I2O_FIN_ACK; - } - if (nat44_is_ses_closed (ses)) - { - nat_free_session_data (sm, ses, thread_index); - nat44_delete_session (sm, ses, thread_index); - return 1; - } - return 0; -} - #endif /* __included_snat_h__ */ diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c index efde4be284c..7a8be98c6fe 100644 --- a/src/plugins/nat/nat44_cli.c +++ b/src/plugins/nat/nat44_cli.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #define UNSUPPORTED_IN_DET_MODE_STR \ @@ -181,6 +182,8 @@ nat44_show_hash_commnad_fn (vlib_main_t * vm, unformat_input_t * input, vec_foreach_index (i, sm->per_thread_data) { tsm = vec_elt_at_index (sm->per_thread_data, i); + vlib_cli_output (vm, "-------- thread %d %s --------\n", + i, vlib_worker_threads[i].name); vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->in2out, verbose); vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->out2in, verbose); vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->user_hash, verbose); @@ -292,7 +295,7 @@ add_address_command_fn (vlib_main_t * vm, count = (end_host_order - start_host_order) + 1; if (count > 1024) - clib_warning ("%U - %U, %d addresses...", + nat_log_info ("%U - %U, %d addresses...", format_ip4_address, &start_addr, format_ip4_address, &end_addr, count); @@ -942,6 +945,8 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input, { tsm = vec_elt_at_index (sm->per_thread_data, i); + vlib_cli_output (vm, "-------- thread %d %s --------\n", + i, vlib_worker_threads[i].name); pool_foreach (u, tsm->users, ({ vlib_cli_output (vm, " %U", format_snat_user, tsm, u, verbose); diff --git a/src/plugins/nat/nat64.c b/src/plugins/nat/nat64.c index 0b7536f21a7..53c2caba2fa 100644 --- a/src/plugins/nat/nat64.c +++ b/src/plugins/nat/nat64.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/nat/nat64_cli.c b/src/plugins/nat/nat64_cli.c index 5b46feddb49..c2639f4fb16 100644 --- a/src/plugins/nat/nat64_cli.c +++ b/src/plugins/nat/nat64_cli.c @@ -19,6 +19,7 @@ #include #include +#include #include static clib_error_t * diff --git a/src/plugins/nat/nat64_db.c b/src/plugins/nat/nat64_db.c index 3edc1a43006..9ff68c80282 100644 --- a/src/plugins/nat/nat64_db.c +++ b/src/plugins/nat/nat64_db.c @@ -18,6 +18,7 @@ */ #include #include +#include #include int diff --git a/src/plugins/nat/nat64_in2out.c b/src/plugins/nat/nat64_in2out.c index ef322d5b60d..603b30ee11a 100644 --- a/src/plugins/nat/nat64_in2out.c +++ b/src/plugins/nat/nat64_in2out.c @@ -19,6 +19,7 @@ #include #include +#include #include #include diff --git a/src/plugins/nat/nat64_out2in.c b/src/plugins/nat/nat64_out2in.c index 17513c5efb8..f43d3e081b4 100644 --- a/src/plugins/nat/nat64_out2in.c +++ b/src/plugins/nat/nat64_out2in.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include diff --git a/src/plugins/nat/nat_api.c b/src/plugins/nat/nat_api.c index 11a6f0fee04..f5f41619b33 100644 --- a/src/plugins/nat/nat_api.c +++ b/src/plugins/nat/nat_api.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -444,7 +445,7 @@ static void vrf_id = clib_host_to_net_u32 (mp->vrf_id); if (count > 1024) - clib_warning ("%U - %U, %d addresses...", + nat_log_info ("%U - %U, %d addresses...", format_ip4_address, mp->first_ip_address, format_ip4_address, mp->last_ip_address, count); diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h new file mode 100644 index 00000000000..db5b295f938 --- /dev/null +++ b/src/plugins/nat/nat_inlines.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2018 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @brief The NAT inline functions + */ + +#ifndef __included_nat_inlines_h__ +#define __included_nat_inlines_h__ + +#include + +always_inline u32 +ip_proto_to_snat_proto (u8 ip_proto) +{ + u32 snat_proto = ~0; + + snat_proto = (ip_proto == IP_PROTOCOL_UDP) ? SNAT_PROTOCOL_UDP : snat_proto; + snat_proto = (ip_proto == IP_PROTOCOL_TCP) ? SNAT_PROTOCOL_TCP : snat_proto; + snat_proto = + (ip_proto == IP_PROTOCOL_ICMP) ? SNAT_PROTOCOL_ICMP : snat_proto; + snat_proto = + (ip_proto == IP_PROTOCOL_ICMP6) ? SNAT_PROTOCOL_ICMP : snat_proto; + + return snat_proto; +} + +always_inline u8 +snat_proto_to_ip_proto (snat_protocol_t snat_proto) +{ + u8 ip_proto = ~0; + + ip_proto = (snat_proto == SNAT_PROTOCOL_UDP) ? IP_PROTOCOL_UDP : ip_proto; + ip_proto = (snat_proto == SNAT_PROTOCOL_TCP) ? IP_PROTOCOL_TCP : ip_proto; + ip_proto = (snat_proto == SNAT_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP : ip_proto; + + return ip_proto; +} + +static_always_inline u8 +icmp_is_error_message (icmp46_header_t * icmp) +{ + switch (icmp->type) + { + case ICMP4_destination_unreachable: + case ICMP4_time_exceeded: + case ICMP4_parameter_problem: + case ICMP4_source_quench: + case ICMP4_redirect: + case ICMP4_alternate_host_address: + return 1; + } + return 0; +} + +always_inline u8 +is_interface_addr (snat_main_t * sm, vlib_node_runtime_t * node, + u32 sw_if_index0, u32 ip4_addr) +{ + snat_runtime_t *rt = (snat_runtime_t *) node->runtime_data; + ip4_address_t *first_int_addr; + + if (PREDICT_FALSE (rt->cached_sw_if_index != sw_if_index0)) + { + first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index0, + 0 /* just want the address */ ); + rt->cached_sw_if_index = sw_if_index0; + if (first_int_addr) + rt->cached_ip4_address = first_int_addr->as_u32; + else + rt->cached_ip4_address = 0; + } + + if (PREDICT_FALSE (ip4_addr == rt->cached_ip4_address)) + return 1; + else + return 0; +} + +always_inline u8 +maximum_sessions_exceeded (snat_main_t * sm, u32 thread_index) +{ + if (pool_elts (sm->per_thread_data[thread_index].sessions) >= + sm->max_translations) + return 1; + + return 0; +} + +always_inline void +nat_send_all_to_node (vlib_main_t * vm, u32 * bi_vector, + vlib_node_runtime_t * node, vlib_error_t * error, + u32 next) +{ + u32 n_left_from, *from, next_index, *to_next, n_left_to_next; + + from = bi_vector; + n_left_from = vec_len (bi_vector); + next_index = node->cached_next_index; + while (n_left_from > 0) + { + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0 = to_next[0] = from[0]; + from += 1; + n_left_from -= 1; + to_next += 1; + n_left_to_next -= 1; + vlib_buffer_t *p0 = vlib_get_buffer (vm, bi0); + p0->error = *error; + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } +} + +always_inline void +user_session_increment (snat_main_t * sm, snat_user_t * u, u8 is_static) +{ + if (u->nsessions + u->nstaticsessions < sm->max_translations_per_user) + { + if (is_static) + u->nstaticsessions++; + else + u->nsessions++; + } +} + +always_inline void +nat44_delete_session (snat_main_t * sm, snat_session_t * ses, + u32 thread_index) +{ + snat_main_per_thread_data_t *tsm = vec_elt_at_index (sm->per_thread_data, + thread_index); + clib_bihash_kv_8_8_t kv, value; + snat_user_key_t u_key; + snat_user_t *u; + + nat_log_debug ("session deleted %U", format_snat_session, tsm, ses); + u_key.addr = ses->in2out.addr; + u_key.fib_index = ses->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); + if (snat_is_session_static (ses)) + u->nstaticsessions--; + else + u->nsessions--; + } + clib_dlist_remove (tsm->list_pool, ses->per_user_index); + pool_put_index (tsm->list_pool, ses->per_user_index); + pool_put (tsm->sessions, ses); +} + +/** \brief Set TCP session state. + @return 1 if session was closed, otherwise 0 +*/ +always_inline int +nat44_set_tcp_session_state_i2o (snat_main_t * sm, snat_session_t * ses, + tcp_header_t * tcp, u32 thread_index) +{ + if (tcp->flags & TCP_FLAG_FIN) + { + ses->i2o_fin_seq = clib_net_to_host_u32 (tcp->seq_number); + ses->state |= NAT44_SES_I2O_FIN; + } + if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN)) + { + if (clib_net_to_host_u32 (tcp->ack_number) > ses->o2i_fin_seq) + ses->state |= NAT44_SES_O2I_FIN_ACK; + } + if (nat44_is_ses_closed (ses)) + { + nat_log_debug ("TCP close connection %U", format_snat_session, + &sm->per_thread_data[thread_index], ses); + nat_free_session_data (sm, ses, thread_index); + nat44_delete_session (sm, ses, thread_index); + return 1; + } + return 0; +} + +always_inline int +nat44_set_tcp_session_state_o2i (snat_main_t * sm, snat_session_t * ses, + tcp_header_t * tcp, u32 thread_index) +{ + if (tcp->flags & TCP_FLAG_FIN) + { + ses->o2i_fin_seq = clib_net_to_host_u32 (tcp->seq_number); + ses->state |= NAT44_SES_O2I_FIN; + } + if ((tcp->flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_FIN)) + { + if (clib_net_to_host_u32 (tcp->ack_number) > ses->i2o_fin_seq) + ses->state |= NAT44_SES_I2O_FIN_ACK; + } + if (nat44_is_ses_closed (ses)) + { + nat_log_debug ("TCP close connection %U", format_snat_session, + &sm->per_thread_data[thread_index], ses); + nat_free_session_data (sm, ses, thread_index); + nat44_delete_session (sm, ses, thread_index); + return 1; + } + return 0; +} + +always_inline void +nat44_session_update_counters (snat_session_t * s, f64 now, uword bytes) +{ + s->last_heard = now; + s->total_pkts++; + s->total_bytes += bytes; +} + +/** \brief Per-user LRU list maintenance */ +always_inline void +nat44_session_update_lru (snat_main_t * sm, snat_session_t * s, + u32 thread_index) +{ + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, + s->per_user_index); + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, + s->per_user_list_head_index, s->per_user_index); +} + +#endif /* __included_nat_inlines_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/nat/nat_ipfix_logging.c b/src/plugins/nat/nat_ipfix_logging.c index 0f291337b0c..4a61fb03f55 100644 --- a/src/plugins/nat/nat_ipfix_logging.c +++ b/src/plugins/nat/nat_ipfix_logging.c @@ -17,6 +17,7 @@ #include #include +#include #include snat_ipfix_logging_main_t snat_ipfix_logging_main; diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c index c7eece8897c..83e1426a413 100755 --- a/src/plugins/nat/out2in.c +++ b/src/plugins/nat/out2in.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -113,7 +114,8 @@ _(NO_TRANSLATION, "No translation") \ _(MAX_SESSIONS_EXCEEDED, "Maximum sessions exceeded") \ _(DROP_FRAGMENT, "Drop fragment") \ _(MAX_REASS, "Maximum reassemblies exceeded") \ -_(MAX_FRAG, "Maximum fragments per reassembly exceeded") +_(MAX_FRAG, "Maximum fragments per reassembly exceeded")\ +_(FQ_CONGESTED, "Handoff frame queue congested") typedef enum { #define _(sym,str) SNAT_OUT2IN_ERROR_##sym, @@ -168,6 +170,7 @@ create_session_for_static_mapping (snat_main_t *sm, if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) { b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED]; + nat_log_notice ("maximum sessions exceeded"); return 0; } @@ -177,14 +180,14 @@ create_session_for_static_mapping (snat_main_t *sm, u = nat_user_get_or_create (sm, &in2out.addr, in2out.fib_index, thread_index); if (!u) { - clib_warning ("create NAT user failed"); + nat_log_warn ("create NAT user failed"); return 0; } s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) { - clib_warning ("create NAT session failed"); + nat_log_warn ("create NAT session failed"); return 0; } @@ -202,13 +205,13 @@ create_session_for_static_mapping (snat_main_t *sm, kv0.value = s - sm->per_thread_data[thread_index].sessions; if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].in2out, &kv0, 1 /* is_add */)) - clib_warning ("in2out key add failed"); + nat_log_notice ("in2out key add failed"); kv0.key = s->out2in.as_u64; if (clib_bihash_add_del_8_8 (&sm->per_thread_data[thread_index].out2in, &kv0, 1 /* is_add */)) - clib_warning ("out2in key add failed"); + nat_log_notice ("out2in key add failed"); /* log NAT event */ snat_ipfix_logging_nat44_ses_create(s->in2out.addr.as_u32, @@ -381,14 +384,14 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index, u = nat_user_get_or_create (sm, &ip->dst_address, sm->inside_fib_index, thread_index); if (!u) { - clib_warning ("create NAT user failed"); + nat_log_warn ("create NAT user failed"); return; } s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) { - clib_warning ("create NAT session failed"); + nat_log_warn ("create NAT session failed"); return; } @@ -405,7 +408,7 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index, kv.value = s - tsm->sessions; if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &kv, 1)) - clib_warning ("in2out_ed key add failed"); + nat_log_notice ("in2out_ed key add failed"); } if (ip->protocol == IP_PROTOCOL_TCP) @@ -415,12 +418,9 @@ create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip, u32 rx_fib_index, return; } /* Per-user LRU list maintenance */ - clib_dlist_remove (tsm->list_pool, s->per_user_index); - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); + nat44_session_update_lru (sm, s, thread_index); /* Accounting */ - s->last_heard = now; - s->total_pkts++; + nat44_session_update_counters (s, now, 0); } /** @@ -789,15 +789,10 @@ static inline u32 icmp_out2in_slow_path (snat_main_t *sm, if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0)) { /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (sm->vlib_main, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (sm->vlib_main, b0)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); + nat44_session_update_lru (sm, s0, thread_index); } return next0; } @@ -844,6 +839,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) { b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED]; + nat_log_notice ("maximum sessions exceeded"); return 0; } @@ -866,7 +862,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, thread_index); if (!u) { - clib_warning ("create NAT user failed"); + nat_log_warn ("create NAT user failed"); return 0; } @@ -874,7 +870,7 @@ snat_out2in_unknown_proto (snat_main_t *sm, s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) { - clib_warning ("create NAT session failed"); + nat_log_warn ("create NAT session failed"); return 0; } @@ -893,14 +889,14 @@ snat_out2in_unknown_proto (snat_main_t *sm, /* Add to lookup tables */ s_kv.value = s - tsm->sessions; if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1)) - clib_warning ("out2in key add failed"); + nat_log_notice ("out2in key add failed"); key.l_addr = ip->dst_address; key.fib_index = m->fib_index; s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1)) - clib_warning ("in2out key add failed"); + nat_log_notice ("in2out key add failed"); } /* Update IP checksum */ @@ -911,13 +907,10 @@ snat_out2in_unknown_proto (snat_main_t *sm, vnet_buffer(b)->sw_if_index[VLIB_TX] = s->in2out.fib_index; /* Accounting */ - s->last_heard = now; - s->total_pkts++; - s->total_bytes += vlib_buffer_length_in_chain (vm, b); + nat44_session_update_counters (s, now, + vlib_buffer_length_in_chain (vm, b)); /* Per-user LRU list maintenance */ - clib_dlist_remove (tsm->list_pool, s->per_user_index); - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); + nat44_session_update_lru (sm, s, thread_index); return s; } @@ -969,6 +962,7 @@ snat_out2in_lb (snat_main_t *sm, if (PREDICT_FALSE (maximum_sessions_exceeded(sm, thread_index))) { b->error = node->errors[SNAT_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED]; + nat_log_notice ("maximum sessions exceeded"); return 0; } @@ -983,14 +977,14 @@ snat_out2in_lb (snat_main_t *sm, thread_index); if (!u) { - clib_warning ("create NAT user failed"); + nat_log_warn ("create NAT user failed"); return 0; } s = nat_session_alloc_or_recycle (sm, u, thread_index); if (!s) { - clib_warning ("create NAT session failed"); + nat_log_warn ("create NAT session failed"); return 0; } @@ -1008,7 +1002,7 @@ snat_out2in_lb (snat_main_t *sm, /* Add to lookup tables */ s_kv.value = s - tsm->sessions; if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &s_kv, 1)) - clib_warning ("out2in-ed key add failed"); + nat_log_notice ("out2in-ed key add failed"); if (twice_nat == TWICE_NAT || (twice_nat == TWICE_NAT_SELF && @@ -1034,7 +1028,7 @@ snat_out2in_lb (snat_main_t *sm, s_kv.key[0] = key.as_u64[0]; s_kv.key[1] = key.as_u64[1]; if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &s_kv, 1)) - clib_warning ("in2out-ed key add failed"); + nat_log_notice ("in2out-ed key add failed"); } new_addr = ip->dst_address.as_u32 = s->in2out.addr.as_u32; @@ -1085,13 +1079,9 @@ snat_out2in_lb (snat_main_t *sm, } /* Accounting */ - s->last_heard = now; - s->total_pkts++; - s->total_bytes += vlib_buffer_length_in_chain (vm, b); + nat44_session_update_counters (s, now, vlib_buffer_length_in_chain (vm, b)); /* Per-user LRU list maintenance */ - clib_dlist_remove (tsm->list_pool, s->per_user_index); - clib_dlist_addtail (tsm->list_pool, s->per_user_list_head_index, - s->per_user_index); + nat44_session_update_lru (sm, s, thread_index); return s; } @@ -1321,15 +1311,10 @@ snat_out2in_node_fn (vlib_main_t * vm, } /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (vm, b0)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); + nat44_session_update_lru (sm, s0, thread_index); trace0: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1499,15 +1484,10 @@ snat_out2in_node_fn (vlib_main_t * vm, } /* Accounting */ - s1->last_heard = now; - s1->total_pkts++; - s1->total_bytes += vlib_buffer_length_in_chain (vm, b1); + nat44_session_update_counters (s1, now, + vlib_buffer_length_in_chain (vm, b1)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s1->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s1->per_user_list_head_index, - s1->per_user_index); + nat44_session_update_lru (sm, s1, thread_index); trace1: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1713,15 +1693,10 @@ snat_out2in_node_fn (vlib_main_t * vm, } /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (vm, b0)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); + nat44_session_update_lru (sm, s0, thread_index); trace00: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -1858,6 +1833,7 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, { next0 = SNAT_OUT2IN_NEXT_DROP; b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_REASS]; + nat_log_notice ("maximum reassemblies exceeded"); goto trace0; } @@ -1934,6 +1910,7 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, if (nat_ip4_reass_add_fragment (reass0, bi0)) { b0->error = node->errors[SNAT_OUT2IN_ERROR_MAX_FRAG]; + nat_log_notice ("maximum fragments per reassembly exceeded"); next0 = SNAT_OUT2IN_NEXT_DROP; goto trace0; } @@ -1982,15 +1959,10 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, } /* Accounting */ - s0->last_heard = now; - s0->total_pkts++; - s0->total_bytes += vlib_buffer_length_in_chain (vm, b0); + nat44_session_update_counters (s0, now, + vlib_buffer_length_in_chain (vm, b0)); /* Per-user LRU list maintenance */ - clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, - s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, - s0->per_user_list_head_index, - s0->per_user_index); + nat44_session_update_lru (sm, s0, thread_index); trace0: if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) @@ -2185,8 +2157,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm, dm0 = snat_det_map_by_out(sm, &ip0->dst_address); if (PREDICT_FALSE(!dm0)) { - clib_warning("unknown dst address: %U", - format_ip4_address, &ip0->dst_address); + nat_log_info ("unknown dst address: %U", + format_ip4_address, &ip0->dst_address); next0 = SNAT_OUT2IN_NEXT_DROP; b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace0; @@ -2198,12 +2170,12 @@ snat_det_out2in_node_fn (vlib_main_t * vm, ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64); if (PREDICT_FALSE(!ses0)) { - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &ip0->src_address, - clib_net_to_host_u16 (tcp0->src), - format_ip4_address, &ip0->dst_address, - clib_net_to_host_u16 (tcp0->dst), - format_ip4_address, &new_addr0); + nat_log_info ("no match src %U:%d dst %U:%d for user %U", + format_ip4_address, &ip0->src_address, + clib_net_to_host_u16 (tcp0->src), + format_ip4_address, &ip0->dst_address, + clib_net_to_host_u16 (tcp0->dst), + format_ip4_address, &new_addr0); next0 = SNAT_OUT2IN_NEXT_DROP; b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace0; @@ -2301,8 +2273,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm, dm1 = snat_det_map_by_out(sm, &ip1->dst_address); if (PREDICT_FALSE(!dm1)) { - clib_warning("unknown dst address: %U", - format_ip4_address, &ip1->dst_address); + nat_log_info ("unknown dst address: %U", + format_ip4_address, &ip1->dst_address); next1 = SNAT_OUT2IN_NEXT_DROP; b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace1; @@ -2314,12 +2286,12 @@ snat_det_out2in_node_fn (vlib_main_t * vm, ses1 = snat_det_get_ses_by_out (dm1, &new_addr1, key1.as_u64); if (PREDICT_FALSE(!ses1)) { - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &ip1->src_address, - clib_net_to_host_u16 (tcp1->src), - format_ip4_address, &ip1->dst_address, - clib_net_to_host_u16 (tcp1->dst), - format_ip4_address, &new_addr1); + nat_log_info ("no match src %U:%d dst %U:%d for user %U", + format_ip4_address, &ip1->src_address, + clib_net_to_host_u16 (tcp1->src), + format_ip4_address, &ip1->dst_address, + clib_net_to_host_u16 (tcp1->dst), + format_ip4_address, &new_addr1); next1 = SNAT_OUT2IN_NEXT_DROP; b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace1; @@ -2450,8 +2422,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm, dm0 = snat_det_map_by_out(sm, &ip0->dst_address); if (PREDICT_FALSE(!dm0)) { - clib_warning("unknown dst address: %U", - format_ip4_address, &ip0->dst_address); + nat_log_info ("unknown dst address: %U", + format_ip4_address, &ip0->dst_address); next0 = SNAT_OUT2IN_NEXT_DROP; b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace00; @@ -2463,12 +2435,12 @@ snat_det_out2in_node_fn (vlib_main_t * vm, ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64); if (PREDICT_FALSE(!ses0)) { - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &ip0->src_address, - clib_net_to_host_u16 (tcp0->src), - format_ip4_address, &ip0->dst_address, - clib_net_to_host_u16 (tcp0->dst), - format_ip4_address, &new_addr0); + nat_log_info ("no match src %U:%d dst %U:%d for user %U", + format_ip4_address, &ip0->src_address, + clib_net_to_host_u16 (tcp0->src), + format_ip4_address, &ip0->dst_address, + clib_net_to_host_u16 (tcp0->dst), + format_ip4_address, &new_addr0); next0 = SNAT_OUT2IN_NEXT_DROP; b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; goto trace00; @@ -2652,8 +2624,8 @@ u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, dont_translate = 1; goto out; } - clib_warning("unknown dst address: %U", - format_ip4_address, &ip0->dst_address); + nat_log_info ("unknown dst address: %U", + format_ip4_address, &ip0->dst_address); goto out; } @@ -2670,12 +2642,12 @@ u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, dont_translate = 1; goto out; } - clib_warning("no match src %U:%d dst %U:%d for user %U", - format_ip4_address, &key0.ext_host_addr, - clib_net_to_host_u16 (key0.ext_host_port), - format_ip4_address, &out_addr, - clib_net_to_host_u16 (key0.out_port), - format_ip4_address, &new_addr0); + nat_log_info ("no match src %U:%d dst %U:%d for user %U", + format_ip4_address, &key0.ext_host_addr, + clib_net_to_host_u16 (key0.ext_host_port), + format_ip4_address, &out_addr, + clib_net_to_host_u16 (key0.out_port), + format_ip4_address, &new_addr0); b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; next0 = SNAT_OUT2IN_NEXT_DROP; goto out; @@ -2717,17 +2689,19 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, { snat_main_t *sm = &snat_main; vlib_thread_main_t *tm = vlib_get_thread_main (); - u32 n_left_from, *from, *to_next = 0; + u32 n_left_from, *from, *to_next = 0, *to_next_drop = 0; static __thread vlib_frame_queue_elt_t **handoff_queue_elt_by_worker_index; static __thread vlib_frame_queue_t **congested_handoff_queue_by_worker_index = 0; vlib_frame_queue_elt_t *hf = 0; + vlib_frame_queue_t *fq; vlib_frame_t *f = 0; int i; u32 n_left_to_next_worker = 0, *to_next_worker = 0; u32 next_worker_index = 0; u32 current_worker_index = ~0; u32 thread_index = vlib_get_thread_index (); + vlib_frame_t *d = 0; ASSERT (vec_len (sm->workers)); @@ -2736,7 +2710,7 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, vec_validate (handoff_queue_elt_by_worker_index, tm->n_vlib_mains - 1); vec_validate_init_empty (congested_handoff_queue_by_worker_index, - sm->first_worker_index + sm->num_workers - 1, + tm->n_vlib_mains - 1, (vlib_frame_queue_t *) (~0)); } @@ -2771,6 +2745,26 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, if (next_worker_index != current_worker_index) { + fq = is_vlib_frame_queue_congested ( + sm->fq_out2in_index, next_worker_index, NAT_FQ_NELTS - 2, + congested_handoff_queue_by_worker_index); + + if (fq) + { + /* if this is 1st frame */ + if (!d) + { + d = vlib_get_frame_to_node (vm, sm->error_node_index); + to_next_drop = vlib_frame_vector_args (d); + } + + to_next_drop[0] = bi0; + to_next_drop += 1; + d->n_vectors++; + b0->error = node->errors[SNAT_OUT2IN_ERROR_FQ_CONGESTED]; + goto trace0; + } + if (hf) hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; @@ -2812,6 +2806,7 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, f->n_vectors++; } +trace0: if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) { @@ -2825,6 +2820,9 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, if (f) vlib_put_frame_to_node (vm, sm->out2in_node_index, f); + if (d) + vlib_put_frame_to_node (vm, sm->error_node_index, d); + if (hf) hf->n_vectors = VLIB_FRAME_SIZE - n_left_to_next_worker; @@ -2861,6 +2859,9 @@ VLIB_REGISTER_NODE (snat_out2in_worker_handoff_node) = { .format_trace = format_snat_out2in_worker_handoff_trace, .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(snat_out2in_error_strings), + .error_strings = snat_out2in_error_strings, + .n_next_nodes = 1, .next_nodes = { diff --git a/test/test_nat.py b/test/test_nat.py index e2f34657d25..ad2b9649b7d 100644 --- a/test/test_nat.py +++ b/test/test_nat.py @@ -826,6 +826,7 @@ class TestNAT44(MethodHolder): @classmethod def setUpClass(cls): super(TestNAT44, cls).setUpClass() + cls.vapi.cli("set log class nat level debug") try: cls.tcp_port_in = 6303 @@ -2582,7 +2583,8 @@ class TestNAT44(MethodHolder): self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture(0) + self.pg1.assert_nothing_captured() + sleep(1) self.vapi.cli("ipfix flush") # FIXME this should be an API call capture = self.pg3.get_capture(9) ipfix = IPFIXDecoder() @@ -2639,7 +2641,8 @@ class TestNAT44(MethodHolder): self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - self.pg1.get_capture(0) + self.pg1.assert_nothing_captured() + sleep(1) self.vapi.cli("ipfix flush") # FIXME this should be an API call capture = self.pg3.get_capture(9) ipfix = IPFIXDecoder() @@ -2698,7 +2701,7 @@ class TestNAT44(MethodHolder): self.pg2.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture(0) + self.pg1.assert_nothing_captured() # remove addresses and verify self.nat44_add_address(self.nat_addr, is_add=0) @@ -2711,7 +2714,7 @@ class TestNAT44(MethodHolder): self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture(0) + self.pg1.assert_nothing_captured() p = (Ether(src=self.pg1.remote_mac, dst='ff:ff:ff:ff:ff:ff') / ARP(op=ARP.who_has, pdst=static_addr, @@ -2719,7 +2722,7 @@ class TestNAT44(MethodHolder): self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture(0) + self.pg1.assert_nothing_captured() def test_vrf_mode(self): """ NAT44 tenant VRF aware address pool mode """ @@ -3117,7 +3120,7 @@ class TestNAT44(MethodHolder): self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg0.get_capture(1) + self.pg0.get_capture(1) p = (Ether(dst=self.pg0.local_mac, src=host.mac) / IP(src=host.ip4, dst=server_nat_ip) / @@ -3608,7 +3611,7 @@ class TestNAT44(MethodHolder): self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - capture = self.pg1.get_capture(len(pkts)) + self.pg1.get_capture(len(pkts)) sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, 0) nsessions = len(sessions) @@ -4018,7 +4021,8 @@ class TestNAT44(MethodHolder): self.pg0.add_stream(pkts[-1]) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - frags = self.pg1.get_capture(0) + self.pg1.assert_nothing_captured() + sleep(1) self.vapi.cli("ipfix flush") # FIXME this should be an API call capture = self.pg3.get_capture(9) ipfix = IPFIXDecoder() @@ -4042,7 +4046,14 @@ class TestNAT44(MethodHolder): def test_tcp_session_close_in(self): """ Close TCP session from inside network """ + self.tcp_port_out = 10505 self.nat44_add_address(self.nat_addr) + self.nat44_add_static_mapping(self.pg0.remote_ip4, + self.nat_addr, + self.tcp_port_in, + self.tcp_port_out, + proto=IP_PROTOS.tcp, + twice_nat=1) self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index) self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index, is_inside=0) @@ -4052,60 +4063,61 @@ class TestNAT44(MethodHolder): self.initiate_tcp_session(self.pg0, self.pg1) - # close the session from inside - try: - # FIN packet in -> out - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="FA", seq=100, ack=300)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) + # FIN packet in -> out + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="FA", seq=100, ack=300)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.get_capture(1) - pkts = [] + pkts = [] - # ACK packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A", seq=300, ack=101)) - pkts.append(p) + # ACK packet out -> in + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, + flags="A", seq=300, ack=101)) + pkts.append(p) - # FIN packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="FA", seq=300, ack=101)) - pkts.append(p) + # FIN packet out -> in + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, + flags="FA", seq=300, ack=101)) + pkts.append(p) - self.pg1.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(2) + self.pg1.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg0.get_capture(2) - # ACK packet in -> out - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="A", seq=101, ack=301)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) + # ACK packet in -> out + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="A", seq=101, ack=301)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.get_capture(1) - self.initiate_tcp_session(self.pg0, self.pg1) - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, - 0) - self.assertEqual(len(sessions) - start_sessnum, 1) - except: - self.logger.error("TCP session termination failed") - raise + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, + 0) + self.assertEqual(len(sessions) - start_sessnum, 0) def test_tcp_session_close_out(self): """ Close TCP session from outside network """ + self.tcp_port_out = 10505 self.nat44_add_address(self.nat_addr) + self.nat44_add_static_mapping(self.pg0.remote_ip4, + self.nat_addr, + self.tcp_port_in, + self.tcp_port_out, + proto=IP_PROTOS.tcp, + twice_nat=1) self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index) self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index, is_inside=0) @@ -4115,50 +4127,51 @@ class TestNAT44(MethodHolder): self.initiate_tcp_session(self.pg0, self.pg1) - # close the session from outside - try: - # FIN packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="FA", seq=100, ack=300)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) + # FIN packet out -> in + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, + flags="FA", seq=100, ack=300)) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg0.get_capture(1) - # FIN+ACK packet in -> out - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="FA", seq=300, ack=101)) + # FIN+ACK packet in -> out + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="FA", seq=300, ack=101)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.get_capture(1) - # ACK packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A", seq=101, ack=301)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) + # ACK packet out -> in + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, + flags="A", seq=101, ack=301)) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg0.get_capture(1) - self.initiate_tcp_session(self.pg0, self.pg1) - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, - 0) - self.assertEqual(len(sessions) - start_sessnum, 1) - except: - self.logger.error("TCP session termination failed") - raise + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, + 0) + self.assertEqual(len(sessions) - start_sessnum, 0) def test_tcp_session_close_simultaneous(self): """ Close TCP session from inside network """ + self.tcp_port_out = 10505 self.nat44_add_address(self.nat_addr) + self.nat44_add_static_mapping(self.pg0.remote_ip4, + self.nat_addr, + self.tcp_port_in, + self.tcp_port_out, + proto=IP_PROTOS.tcp, + twice_nat=1) self.vapi.nat44_interface_add_del_feature(self.pg0.sw_if_index) self.vapi.nat44_interface_add_del_feature(self.pg1.sw_if_index, is_inside=0) @@ -4168,55 +4181,49 @@ class TestNAT44(MethodHolder): self.initiate_tcp_session(self.pg0, self.pg1) - # close the session from inside - try: - # FIN packet in -> out - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="FA", seq=100, ack=300)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) + # FIN packet in -> out + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="FA", seq=100, ack=300)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.get_capture(1) - # FIN packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="FA", seq=300, ack=100)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) + # FIN packet out -> in + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, + flags="FA", seq=300, ack=100)) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg0.get_capture(1) - # ACK packet in -> out - p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / - TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, - flags="A", seq=101, ack=301)) - self.pg0.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg1.get_capture(1) + # ACK packet in -> out + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="A", seq=101, ack=301)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.get_capture(1) - # ACK packet out -> in - p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / - IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / - TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, - flags="A", seq=301, ack=101)) - self.pg1.add_stream(p) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() - self.pg0.get_capture(1) + # ACK packet out -> in + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, + flags="A", seq=301, ack=101)) + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg0.get_capture(1) - self.initiate_tcp_session(self.pg0, self.pg1) - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, - 0) - self.assertEqual(len(sessions) - start_sessnum, 1) - except: - self.logger.error("TCP session termination failed") - raise + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4n, + 0) + self.assertEqual(len(sessions) - start_sessnum, 0) def tearDown(self): super(TestNAT44, self).tearDown() @@ -4227,8 +4234,10 @@ class TestNAT44(MethodHolder): self.logger.info(self.vapi.cli("show nat44 interface address")) self.logger.info(self.vapi.cli("show nat44 sessions detail")) self.logger.info(self.vapi.cli("show nat virtual-reassembly")) + self.logger.info(self.vapi.cli("show nat44 hash tables detail")) self.vapi.cli("nat addr-port-assignment-alg default") self.clear_nat44() + self.vapi.cli("clear logging") class TestNAT44Out2InDPO(MethodHolder): @@ -4242,6 +4251,7 @@ class TestNAT44Out2InDPO(MethodHolder): @classmethod def setUpClass(cls): super(TestNAT44Out2InDPO, cls).setUpClass() + cls.vapi.cli("set log class nat level debug") try: cls.tcp_port_in = 6303 @@ -4359,6 +4369,7 @@ class TestDeterministicNAT(MethodHolder): @classmethod def setUpClass(cls): super(TestDeterministicNAT, cls).setUpClass() + cls.vapi.cli("set log class nat level debug") try: cls.tcp_port_in = 6303 @@ -5950,7 +5961,8 @@ class TestNAT64(MethodHolder): self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - self.pg1.get_capture(0) + self.pg1.assert_nothing_captured() + sleep(1) self.vapi.cli("ipfix flush") # FIXME this should be an API call capture = self.pg3.get_capture(9) ipfix = IPFIXDecoder() @@ -5977,7 +5989,8 @@ class TestNAT64(MethodHolder): self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - self.pg1.get_capture(0) + self.pg1.assert_nothing_captured() + sleep(1) self.vapi.cli("ipfix flush") # FIXME this should be an API call capture = self.pg3.get_capture(1) # verify events in data set @@ -6013,7 +6026,8 @@ class TestNAT64(MethodHolder): self.pg0.add_stream(pkts[-1]) self.pg_enable_capture(self.pg_interfaces) self.pg_start() - self.pg1.get_capture(0) + self.pg1.assert_nothing_captured() + sleep(1) self.vapi.cli("ipfix flush") # FIXME this should be an API call capture = self.pg3.get_capture(9) ipfix = IPFIXDecoder() -- 2.16.6