diff options
Diffstat (limited to 'src/plugins/nat')
80 files changed, 5411 insertions, 5172 deletions
diff --git a/src/plugins/nat/CMakeLists.txt b/src/plugins/nat/CMakeLists.txt index 2545da6da18..c53e0e39c7c 100644 --- a/src/plugins/nat/CMakeLists.txt +++ b/src/plugins/nat/CMakeLists.txt @@ -62,12 +62,10 @@ add_vpp_plugin(nat44_ei nat44-ei/nat44_ei_in2out.c nat44-ei/nat44_ei_out2in.c nat44-ei/nat44_ei_handoff.c - nat44-ei/nat44_ei_hairpinning.c MULTIARCH_SOURCES nat44-ei/nat44_ei_in2out.c nat44-ei/nat44_ei_out2in.c - nat44-ei/nat44_ei_hairpinning.c API_FILES nat44-ei/nat44_ei.api @@ -199,7 +197,7 @@ add_custom_target(test_pnat-run DEPENDS test_pnat ) -if("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.13" AND "${CMAKE_C_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") +if(VPP_BUILD_TESTS_WITH_COVERAGE) set(TARGET_NAME test_pnat) set(COV_SOURCES ${CMAKE_SOURCE_DIR}/plugins/nat/pnat/pnat.c ${CMAKE_SOURCE_DIR}/plugins/nat/pnat/pnat_node.h ${CMAKE_SOURCE_DIR}/plugins/nat/pnat/pnat_node.c) diff --git a/src/plugins/nat/FEATURE.yaml b/src/plugins/nat/FEATURE.yaml index bbb8586390e..e2efdf5618d 100644 --- a/src/plugins/nat/FEATURE.yaml +++ b/src/plugins/nat/FEATURE.yaml @@ -2,7 +2,7 @@ name: Network Address Translation maintainer: - Ole Troan <ot@cisco.com> - - Filip Varga <fivarga@cisco.com> + - Filip Varga <filipvarga89@gmail.com> features: - NAT44-EI - IPv4 Endpoint Independent NAT - 1:1 NAT diff --git a/src/plugins/nat/det44/det44.api b/src/plugins/nat/det44/det44.api index 7b6aef70883..ddb9c497ea0 100644 --- a/src/plugins/nat/det44/det44.api +++ b/src/plugins/nat/det44/det44.api @@ -39,7 +39,6 @@ autoreply define det44_plugin_enable_disable { u32 inside_vrf; u32 outside_vrf; bool enable; - option status="in_progress"; }; /** \brief Enable/disable DET44 feature on the interface @@ -55,7 +54,6 @@ autoreply define det44_interface_add_del_feature { bool is_add; bool is_inside; vl_api_interface_index_t sw_if_index; - option status="in_progress"; }; /** \brief Dump interfaces with DET44 feature @@ -65,7 +63,6 @@ autoreply define det44_interface_add_del_feature { define det44_interface_dump { u32 client_index; u32 context; - option status="in_progress"; }; /** \brief DET44 interface details response @@ -78,7 +75,6 @@ define det44_interface_details { bool is_inside; bool is_outside; vl_api_interface_index_t sw_if_index; - option status="in_progress"; }; /** \brief Add/delete DET44 mapping diff --git a/src/plugins/nat/det44/det44.c b/src/plugins/nat/det44/det44.c index 1dbbfdfdebe..f251bc9c608 100644 --- a/src/plugins/nat/det44/det44.c +++ b/src/plugins/nat/det44/det44.c @@ -29,7 +29,6 @@ det44_main_t det44_main; -/* *INDENT-OFF* */ VNET_FEATURE_INIT (ip4_det44_in2out, static) = { .arc_name = "ip4-unicast", .node_name = "det44-in2out", @@ -47,7 +46,6 @@ VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER, .description = "Deterministic NAT (CGN)", }; -/* *INDENT-ON* */ void det44_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index, @@ -150,14 +148,12 @@ snat_det_add_map (ip4_address_t * in_addr, u8 in_plen, } /* Add/del external address range to FIB */ - /* *INDENT-OFF* */ pool_foreach (i, dm->interfaces) { if (det44_interface_is_inside(i)) continue; det44_add_del_addr_to_fib(out_addr, out_plen, i->sw_if_index, is_add); goto out; } - /* *INDENT-ON* */ out: return 0; } @@ -203,7 +199,6 @@ det44_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) // rather make a structure and when enable call is used // then register nodes - /* *INDENT-OFF* */ pool_foreach (tmp, dm->interfaces) { if (tmp->sw_if_index == sw_if_index) { @@ -211,7 +206,6 @@ det44_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) goto out; } } - /* *INDENT-ON* */ out: feature_name = is_inside ? "det44-in2out" : "det44-out2in"; @@ -270,7 +264,6 @@ out: // add/del outside interface fib to registry u8 found = 0; det44_fib_t *outside_fib; - /* *INDENT-OFF* */ vec_foreach (outside_fib, dm->outside_fibs) { if (outside_fib->fib_index == fib_index) @@ -292,7 +285,6 @@ out: break; } } - /* *INDENT-ON* */ if (!is_del && !found) { vec_add2 (dm->outside_fibs, outside_fib, 1); @@ -301,12 +293,10 @@ out: } // add/del outside address to FIB snat_det_map_t *mp; - /* *INDENT-OFF* */ pool_foreach (mp, dm->det_maps) { det44_add_del_addr_to_fib(&mp->out_addr, mp->out_plen, sw_if_index, !is_del); } - /* *INDENT-ON* */ } return 0; } @@ -324,19 +314,29 @@ det44_expire_walk_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, snat_det_session_t *ses; snat_det_map_t *mp; - vlib_process_wait_for_event_or_clock (vm, 10.0); - vlib_process_get_events (vm, NULL); - u32 now = (u32) vlib_time_now (vm); - /* *INDENT-OFF* */ - pool_foreach (mp, dm->det_maps) { - vec_foreach(ses, mp->sessions) - { - /* Delete if session expired */ - if (ses->in_port && (ses->expire < now)) - snat_det_ses_close (mp, ses); - } - } - /* *INDENT-ON* */ + while (1) + { + vlib_process_wait_for_event_or_clock (vm, 10.0); + vlib_process_get_events (vm, NULL); + u32 now = (u32) vlib_time_now (vm); + + if (!plugin_enabled ()) + { + continue; + } + + pool_foreach (mp, dm->det_maps) + { + vec_foreach (ses, mp->sessions) + { + // close expired sessions + if (ses->in_port && (ses->expire < now)) + { + snat_det_ses_close (mp, ses); + } + } + } + } return 0; } @@ -374,10 +374,11 @@ det44_plugin_enable (det44_config_t c) c.inside_vrf_id, dm->fib_src_hi); - det44_create_expire_walk_process (); dm->mss_clamping = 0; dm->config = c; dm->enabled = 1; + + det44_create_expire_walk_process (); return 0; } @@ -395,6 +396,8 @@ det44_plugin_disable () return 1; } + dm->enabled = 0; + // DET44 cleanup (order dependent) // 1) remove interfaces (det44_interface_add_del) removes map ranges from fib // 2) free sessions @@ -428,15 +431,12 @@ det44_plugin_disable () } vec_free (interfaces); - /* *INDENT-OFF* */ pool_foreach (mp, dm->det_maps) { vec_free (mp->sessions); } - /* *INDENT-ON* */ det44_reset_timeouts (); - dm->enabled = 0; pool_free (dm->interfaces); pool_free (dm->det_maps); @@ -467,7 +467,6 @@ det44_update_outside_fib (ip4_main_t * im, if (!vec_len (dm->outside_fibs)) return; - /* *INDENT-OFF* */ pool_foreach (i, dm->interfaces) { if (i->sw_if_index == sw_if_index) @@ -477,7 +476,6 @@ det44_update_outside_fib (ip4_main_t * im, match = 1; } } - /* *INDENT-ON* */ if (!match) return; diff --git a/src/plugins/nat/det44/det44.h b/src/plugins/nat/det44/det44.h index 20dc8b1aec9..e576bfb65e8 100644 --- a/src/plugins/nat/det44/det44.h +++ b/src/plugins/nat/det44/det44.h @@ -229,7 +229,7 @@ plugin_enabled () extern vlib_node_registration_t det44_in2out_node; extern vlib_node_registration_t det44_out2in_node; -int det44_plugin_enable (); +int det44_plugin_enable (det44_config_t); int det44_plugin_disable (); int det44_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del); @@ -279,13 +279,11 @@ snat_det_map_by_user (ip4_address_t * user_addr) { det44_main_t *dm = &det44_main; snat_det_map_t *mp; - /* *INDENT-OFF* */ pool_foreach (mp, dm->det_maps) { if (is_addr_in_net(user_addr, &mp->in_addr, mp->in_plen)) return mp; } - /* *INDENT-ON* */ return 0; } @@ -294,13 +292,11 @@ snat_det_map_by_out (ip4_address_t * out_addr) { det44_main_t *dm = &det44_main; snat_det_map_t *mp; - /* *INDENT-OFF* */ pool_foreach (mp, dm->det_maps) { if (is_addr_in_net(out_addr, &mp->out_addr, mp->out_plen)) return mp; } - /* *INDENT-ON* */ return 0; } diff --git a/src/plugins/nat/det44/det44_api.c b/src/plugins/nat/det44/det44_api.c index 1486180aa99..c7e17dfd147 100644 --- a/src/plugins/nat/det44/det44_api.c +++ b/src/plugins/nat/det44/det44_api.c @@ -67,14 +67,12 @@ vl_api_det44_forward_t_handler (vl_api_det44_forward_t * mp) hi_port = lo_port + m->ports_per_host - 1; send_reply: - /* *INDENT-OFF* */ REPLY_MACRO2 (VL_API_DET44_FORWARD_REPLY, ({ rmp->out_port_lo = ntohs (lo_port); rmp->out_port_hi = ntohs (hi_port); clib_memcpy (rmp->out_addr, &out_addr, 4); })) - /* *INDENT-ON* */ } static void @@ -98,12 +96,10 @@ vl_api_det44_reverse_t_handler (vl_api_det44_reverse_t * mp) snat_det_reverse (m, &out_addr, htons (mp->out_port), &in_addr); send_reply: - /* *INDENT-OFF* */ REPLY_MACRO2 (VL_API_DET44_REVERSE_REPLY, ({ clib_memcpy (rmp->in_addr, &in_addr, 4); })) - /* *INDENT-ON* */ } static void @@ -139,10 +135,8 @@ vl_api_det44_map_dump_t_handler (vl_api_det44_map_dump_t * mp) if (!reg) return; - /* *INDENT-OFF* */ vec_foreach(m, dm->det_maps) sent_det44_map_details(m, reg, mp->context); - /* *INDENT-ON* */ } static void @@ -328,12 +322,10 @@ vl_api_det44_interface_dump_t_handler (vl_api_det44_interface_dump_t * mp) if (!reg) return; - /* *INDENT-OFF* */ pool_foreach (i, dm->interfaces) { det44_send_interface_details(i, reg, mp->context); } - /* *INDENT-ON* */ } static void @@ -359,7 +351,6 @@ vl_api_det44_get_timeouts_t_handler (vl_api_det44_get_timeouts_t * mp) nat_timeouts_t timeouts; int rv = 0; timeouts = det44_get_timeouts (); - /* *INDENT-OFF* */ REPLY_MACRO2 (VL_API_DET44_GET_TIMEOUTS_REPLY, ({ rmp->udp = htonl (timeouts.udp); @@ -367,7 +358,6 @@ vl_api_det44_get_timeouts_t_handler (vl_api_det44_get_timeouts_t * mp) rmp->tcp_transitory = htonl (timeouts.tcp.transitory); rmp->icmp = htonl (timeouts.icmp); })) - /* *INDENT-ON* */ } /* @@ -412,14 +402,12 @@ vl_api_nat_det_forward_t_handler (vl_api_nat_det_forward_t * mp) hi_port = lo_port + m->ports_per_host - 1; send_reply: - /* *INDENT-OFF* */ REPLY_MACRO2 (VL_API_NAT_DET_FORWARD_REPLY, ({ rmp->out_port_lo = ntohs (lo_port); rmp->out_port_hi = ntohs (hi_port); clib_memcpy (rmp->out_addr, &out_addr, 4); })) - /* *INDENT-ON* */ } static void @@ -443,12 +431,10 @@ vl_api_nat_det_reverse_t_handler (vl_api_nat_det_reverse_t * mp) snat_det_reverse (m, &out_addr, htons (mp->out_port), &in_addr); send_reply: - /* *INDENT-OFF* */ REPLY_MACRO2 (VL_API_NAT_DET_REVERSE_REPLY, ({ clib_memcpy (rmp->in_addr, &in_addr, 4); })) - /* *INDENT-ON* */ } static void @@ -484,10 +470,8 @@ vl_api_nat_det_map_dump_t_handler (vl_api_nat_det_map_dump_t * mp) if (!reg) return; - /* *INDENT-OFF* */ vec_foreach(m, dm->det_maps) sent_nat_det_map_details(m, reg, mp->context); - /* *INDENT-ON* */ } static void diff --git a/src/plugins/nat/det44/det44_in2out.c b/src/plugins/nat/det44/det44_in2out.c index 5fe4a9a0658..3f5e05a064c 100644 --- a/src/plugins/nat/det44/det44_in2out.c +++ b/src/plugins/nat/det44/det44_in2out.c @@ -1011,7 +1011,6 @@ VLIB_NODE_FN (det44_in2out_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (det44_in2out_node) = { .name = "det44-in2out", .vector_size = sizeof (u32), @@ -1028,7 +1027,6 @@ VLIB_REGISTER_NODE (det44_in2out_node) = { [DET44_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/det44/det44_inlines.h b/src/plugins/nat/det44/det44_inlines.h index aeb55b385d3..e5e70bbaebc 100644 --- a/src/plugins/nat/det44/det44_inlines.h +++ b/src/plugins/nat/det44/det44_inlines.h @@ -91,7 +91,6 @@ det44_translate (vlib_node_runtime_t * node, u32 sw_if_index0, if (sw_if_index == ~0) { // TODO: go over use cases - /* *INDENT-OFF* */ vec_foreach (outside_fib, dm->outside_fibs) { fei = fib_table_lookup (outside_fib->fib_index, &pfx); @@ -102,18 +101,15 @@ det44_translate (vlib_node_runtime_t * node, u32 sw_if_index0, break; } } - /* *INDENT-ON* */ } if (sw_if_index != ~0) { det44_interface_t *i; - /* *INDENT-OFF* */ pool_foreach (i, dm->interfaces) { /* NAT packet aimed at outside interface */ if ((det44_interface_is_outside (i)) && (sw_if_index == i->sw_if_index)) return 0; } - /* *INDENT-ON* */ } } return 1; diff --git a/src/plugins/nat/det44/det44_out2in.c b/src/plugins/nat/det44/det44_out2in.c index 111bc61c476..ab6acd4f8e9 100644 --- a/src/plugins/nat/det44/det44_out2in.c +++ b/src/plugins/nat/det44/det44_out2in.c @@ -173,6 +173,9 @@ icmp_match_out2in_det (vlib_node_runtime_t * node, } det44_log_info ("unknown dst address: %U", format_ip4_address, &ip0->dst_address); + b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION]; + next0 = DET44_OUT2IN_NEXT_DROP; + goto out; } @@ -815,7 +818,6 @@ VLIB_NODE_FN (det44_out2in_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (det44_out2in_node) = { .name = "det44-out2in", .vector_size = sizeof (u32), @@ -832,7 +834,6 @@ VLIB_REGISTER_NODE (det44_out2in_node) = { [DET44_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/dslite/dslite.c b/src/plugins/nat/dslite/dslite.c index 4fe4422df13..a2654b5a44b 100644 --- a/src/plugins/nat/dslite/dslite.c +++ b/src/plugins/nat/dslite/dslite.c @@ -101,7 +101,6 @@ dslite_init_datastructures (void) u32 b4_buckets = 128; u32 b4_memory_size = 64 << 20; - /* *INDENT-OFF* */ vec_foreach (td, dm->per_thread_data) { clib_bihash_init_24_8 (&td->in2out, "dslite in2out", translation_buckets, @@ -112,7 +111,6 @@ dslite_init_datastructures (void) clib_bihash_init_16_8 (&td->b4_hash, "dslite b4s", b4_buckets, b4_memory_size); } - /* *INDENT-ON* */ dm->is_enabled = 1; } @@ -281,13 +279,11 @@ format_dslite_ce_trace (u8 * s, va_list * args) VLIB_INIT_FUNCTION (dslite_init); -/* *INDENT-OFF* */ VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER, .description = "Dual-Stack Lite", }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/dslite/dslite.h b/src/plugins/nat/dslite/dslite.h index 3c798bf54fe..f05670c9bf5 100644 --- a/src/plugins/nat/dslite/dslite.h +++ b/src/plugins/nat/dslite/dslite.h @@ -61,7 +61,6 @@ typedef struct }; } dslite_session_key_t; -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { nat_session_key_t out2in; @@ -72,7 +71,6 @@ typedef CLIB_PACKED (struct u64 total_bytes; u32 total_pkts; }) dslite_session_t; -/* *INDENT-ON* */ typedef struct { diff --git a/src/plugins/nat/dslite/dslite_api.c b/src/plugins/nat/dslite/dslite_api.c index 420e8212ad9..4bb53c37660 100644 --- a/src/plugins/nat/dslite/dslite_api.c +++ b/src/plugins/nat/dslite/dslite_api.c @@ -53,13 +53,11 @@ vl_api_dslite_get_aftr_addr_t_handler (vl_api_dslite_get_aftr_addr_t * mp) dslite_main_t *dm = &dslite_main; int rv = 0; - /* *INDENT-OFF* */ REPLY_MACRO2 (VL_API_DSLITE_GET_AFTR_ADDR_REPLY, ({ memcpy (rmp->ip4_addr, &dm->aftr_ip4_addr.as_u8, 4); memcpy (rmp->ip6_addr, &dm->aftr_ip6_addr.as_u8, 16); })) - /* *INDENT-ON* */ } static void @@ -88,13 +86,11 @@ vl_api_dslite_get_b4_addr_t_handler (vl_api_dslite_get_b4_addr_t * mp) dslite_main_t *dm = &dslite_main; int rv = 0; - /* *INDENT-OFF* */ REPLY_MACRO2 (VL_API_DSLITE_GET_B4_ADDR_REPLY, ({ memcpy (rmp->ip4_addr, &dm->b4_ip4_addr.as_u8, 4); memcpy (rmp->ip6_addr, &dm->b4_ip6_addr.as_u8, 16); })) - /* *INDENT-ON* */ } static void @@ -154,12 +150,10 @@ vl_api_dslite_address_dump_t_handler (vl_api_dslite_address_dump_t * mp) if (!reg) return; - /* *INDENT-OFF* */ vec_foreach (a, dm->pool.pool_addr) { send_dslite_address_details (a, reg, mp->context); } - /* *INDENT-ON* */ } /* API definitions */ diff --git a/src/plugins/nat/dslite/dslite_ce_decap.c b/src/plugins/nat/dslite/dslite_ce_decap.c index f36a87f8bc1..b5bdafc0e26 100644 --- a/src/plugins/nat/dslite/dslite_ce_decap.c +++ b/src/plugins/nat/dslite/dslite_ce_decap.c @@ -114,7 +114,6 @@ VLIB_NODE_FN (dslite_ce_decap_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (dslite_ce_decap_node) = { .name = "dslite-ce-decap", .vector_size = sizeof (u32), @@ -130,7 +129,6 @@ VLIB_REGISTER_NODE (dslite_ce_decap_node) = { [DSLITE_IN2OUT_NEXT_IP6_ICMP] = "ip6-icmp-input", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/dslite/dslite_ce_encap.c b/src/plugins/nat/dslite/dslite_ce_encap.c index d8d0e400919..19596efd32d 100644 --- a/src/plugins/nat/dslite/dslite_ce_encap.c +++ b/src/plugins/nat/dslite/dslite_ce_encap.c @@ -107,7 +107,6 @@ VLIB_NODE_FN (dslite_ce_encap_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (dslite_ce_encap_node) = { .name = "dslite-ce-encap", .vector_size = sizeof (u32), @@ -122,7 +121,6 @@ VLIB_REGISTER_NODE (dslite_ce_encap_node) = { [DSLITE_CE_ENCAP_NEXT_IP6_LOOKUP] = "ip6-lookup", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/dslite/dslite_cli.c b/src/plugins/nat/dslite/dslite_cli.c index 193cb3fe248..8ed9deb2a2d 100644 --- a/src/plugins/nat/dslite/dslite_cli.c +++ b/src/plugins/nat/dslite/dslite_cli.c @@ -95,12 +95,10 @@ dslite_show_pool_command_fn (vlib_main_t * vm, vlib_cli_output (vm, "DS-Lite pool:"); - /* *INDENT-OFF* */ vec_foreach (a, dm->pool.pool_addr) { vlib_cli_output (vm, "%U", format_ip4_address, &a->addr); } - /* *INDENT-ON* */ return 0; } @@ -267,7 +265,6 @@ dslite_show_sessions_command_fn (vlib_main_t * vm, dslite_per_thread_data_t *td; dslite_b4_t *b4; - /* *INDENT-OFF* */ vec_foreach (td, dm->per_thread_data) { pool_foreach (b4, td->b4s) @@ -275,12 +272,10 @@ dslite_show_sessions_command_fn (vlib_main_t * vm, vlib_cli_output (vm, "%U", format_dslite_b4, td, b4); } } - /* *INDENT-ON* */ return 0; } -/* *INDENT-OFF* */ /*? * @cliexpar @@ -394,7 +389,6 @@ VLIB_CLI_COMMAND (dslite_show_sessions, static) = { .function = dslite_show_sessions_command_fn, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/dslite/dslite_in2out.c b/src/plugins/nat/dslite/dslite_in2out.c index 409c59c218c..522c3cf4123 100644 --- a/src/plugins/nat/dslite/dslite_in2out.c +++ b/src/plugins/nat/dslite/dslite_in2out.c @@ -460,7 +460,6 @@ VLIB_NODE_FN (dslite_in2out_node) (vlib_main_t * vm, return dslite_in2out_node_fn_inline (vm, node, frame, 0); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (dslite_in2out_node) = { .name = "dslite-in2out", .vector_size = sizeof (u32), @@ -477,7 +476,6 @@ VLIB_REGISTER_NODE (dslite_in2out_node) = { [DSLITE_IN2OUT_NEXT_SLOWPATH] = "dslite-in2out-slowpath", }, }; -/* *INDENT-ON* */ VLIB_NODE_FN (dslite_in2out_slowpath_node) (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -486,7 +484,6 @@ VLIB_NODE_FN (dslite_in2out_slowpath_node) (vlib_main_t * vm, return dslite_in2out_node_fn_inline (vm, node, frame, 1); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (dslite_in2out_slowpath_node) = { .name = "dslite-in2out-slowpath", .vector_size = sizeof (u32), @@ -503,7 +500,6 @@ VLIB_REGISTER_NODE (dslite_in2out_slowpath_node) = { [DSLITE_IN2OUT_NEXT_SLOWPATH] = "dslite-in2out-slowpath", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/dslite/dslite_out2in.c b/src/plugins/nat/dslite/dslite_out2in.c index c2fa767bd7d..531bbb468bb 100644 --- a/src/plugins/nat/dslite/dslite_out2in.c +++ b/src/plugins/nat/dslite/dslite_out2in.c @@ -266,7 +266,6 @@ VLIB_NODE_FN (dslite_out2in_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (dslite_out2in_node) = { .name = "dslite-out2in", .vector_size = sizeof (u32), @@ -282,7 +281,6 @@ VLIB_REGISTER_NODE (dslite_out2in_node) = { [DSLITE_OUT2IN_NEXT_IP6_LOOKUP] = "ip6-lookup", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/extras/nat_100ks.py b/src/plugins/nat/extras/nat_100ks.py index c85a4591cd3..4e8dc2486d6 100644 --- a/src/plugins/nat/extras/nat_100ks.py +++ b/src/plugins/nat/extras/nat_100ks.py @@ -1,35 +1,39 @@ from trex_stl_lib.api import * -class STLS1: - def create_stream (self): - base_pkt = Ether()/IP(dst="2.2.0.1")/UDP(dport=12) +class STLS1: + def create_stream(self): + base_pkt = Ether() / IP(dst="2.2.0.1") / UDP(dport=12) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len vm = STLVM() - vm.tuple_var(name="tuple", ip_min="10.0.0.3", ip_max="10.0.3.234", port_min=1025, port_max=1124, limit_flows = 100000) + vm.tuple_var( + name="tuple", + ip_min="10.0.0.3", + ip_max="10.0.3.234", + port_min=1025, + port_max=1124, + limit_flows=100000, + ) vm.write(fv_name="tuple.ip", pkt_offset="IP.src") vm.fix_chksum() vm.write(fv_name="tuple.port", pkt_offset="UDP.sport") - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) - def get_streams (self, direction = 0, **kwargs): + def get_streams(self, direction=0, **kwargs): return [self.create_stream()] # dynamic load - used for trex console or simulator def register(): return STLS1() - - - diff --git a/src/plugins/nat/extras/nat_10Ms.py b/src/plugins/nat/extras/nat_10Ms.py index 6ce62a0b5e7..96a18ec018a 100644 --- a/src/plugins/nat/extras/nat_10Ms.py +++ b/src/plugins/nat/extras/nat_10Ms.py @@ -1,35 +1,39 @@ from trex_stl_lib.api import * -class STLS1: - def create_stream (self): - base_pkt = Ether()/IP(dst="2.2.0.1")/UDP(dport=12) +class STLS1: + def create_stream(self): + base_pkt = Ether() / IP(dst="2.2.0.1") / UDP(dport=12) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len vm = STLVM() - vm.tuple_var(name="tuple", ip_min="10.0.0.3", ip_max="10.1.134.162", port_min=1025, port_max=1124, limit_flows=10000000) + vm.tuple_var( + name="tuple", + ip_min="10.0.0.3", + ip_max="10.1.134.162", + port_min=1025, + port_max=1124, + limit_flows=10000000, + ) vm.write(fv_name="tuple.ip", pkt_offset="IP.src") vm.fix_chksum() vm.write(fv_name="tuple.port", pkt_offset="UDP.sport") - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) - def get_streams (self, direction = 0, **kwargs): + def get_streams(self, direction=0, **kwargs): return [self.create_stream()] # dynamic load - used for trex console or simulator def register(): return STLS1() - - - diff --git a/src/plugins/nat/extras/nat_10ks.py b/src/plugins/nat/extras/nat_10ks.py index 33c7196eb9e..c210d5e81d8 100644 --- a/src/plugins/nat/extras/nat_10ks.py +++ b/src/plugins/nat/extras/nat_10ks.py @@ -1,35 +1,39 @@ from trex_stl_lib.api import * -class STLS1: - def create_stream (self): - base_pkt = Ether()/IP(dst="2.2.0.1")/UDP(dport=12) +class STLS1: + def create_stream(self): + base_pkt = Ether() / IP(dst="2.2.0.1") / UDP(dport=12) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len vm = STLVM() - vm.tuple_var(name="tuple", ip_min="10.0.0.3", ip_max="10.0.0.102", port_min=1025, port_max=1124, limit_flows = 10000) + vm.tuple_var( + name="tuple", + ip_min="10.0.0.3", + ip_max="10.0.0.102", + port_min=1025, + port_max=1124, + limit_flows=10000, + ) vm.write(fv_name="tuple.ip", pkt_offset="IP.src") vm.fix_chksum() vm.write(fv_name="tuple.port", pkt_offset="UDP.sport") - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) - def get_streams (self, direction = 0, **kwargs): + def get_streams(self, direction=0, **kwargs): return [self.create_stream()] # dynamic load - used for trex console or simulator def register(): return STLS1() - - - diff --git a/src/plugins/nat/extras/nat_1Ms.py b/src/plugins/nat/extras/nat_1Ms.py index 73a91a70985..7271cf73781 100644 --- a/src/plugins/nat/extras/nat_1Ms.py +++ b/src/plugins/nat/extras/nat_1Ms.py @@ -1,35 +1,39 @@ from trex_stl_lib.api import * -class STLS1: - def create_stream (self): - base_pkt = Ether()/IP(dst="2.2.0.1")/UDP(dport=12) +class STLS1: + def create_stream(self): + base_pkt = Ether() / IP(dst="2.2.0.1") / UDP(dport=12) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len vm = STLVM() - vm.tuple_var(name="tuple", ip_min="10.0.0.3", ip_max="10.0.39.18", port_min=1025, port_max=1124, limit_flows = 1000000) + vm.tuple_var( + name="tuple", + ip_min="10.0.0.3", + ip_max="10.0.39.18", + port_min=1025, + port_max=1124, + limit_flows=1000000, + ) vm.write(fv_name="tuple.ip", pkt_offset="IP.src") vm.fix_chksum() vm.write(fv_name="tuple.port", pkt_offset="UDP.sport") - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) - def get_streams (self, direction = 0, **kwargs): + def get_streams(self, direction=0, **kwargs): return [self.create_stream()] # dynamic load - used for trex console or simulator def register(): return STLS1() - - - diff --git a/src/plugins/nat/extras/nat_out2in_100ks.py b/src/plugins/nat/extras/nat_out2in_100ks.py index 55ab5d42ee1..911f2cefda4 100644 --- a/src/plugins/nat/extras/nat_out2in_100ks.py +++ b/src/plugins/nat/extras/nat_out2in_100ks.py @@ -1,35 +1,39 @@ from trex_stl_lib.api import * -class STLS1: - def create_stream (self): - base_pkt = Ether()/IP(src="2.2.0.1")/UDP(sport=12) +class STLS1: + def create_stream(self): + base_pkt = Ether() / IP(src="2.2.0.1") / UDP(sport=12) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len vm = STLVM() - vm.tuple_var(name="tuple", ip_min="173.16.1.3", ip_max="173.16.4.234", port_min=1025, port_max=1124, limit_flows = 100000) + vm.tuple_var( + name="tuple", + ip_min="173.16.1.3", + ip_max="173.16.4.234", + port_min=1025, + port_max=1124, + limit_flows=100000, + ) vm.write(fv_name="tuple.ip", pkt_offset="IP.dst") vm.fix_chksum() vm.write(fv_name="tuple.port", pkt_offset="UDP.dport") - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) - def get_streams (self, direction = 0, **kwargs): + def get_streams(self, direction=0, **kwargs): return [self.create_stream()] # dynamic load - used for trex console or simulator def register(): return STLS1() - - - diff --git a/src/plugins/nat/extras/nat_out2in_10Ms.py b/src/plugins/nat/extras/nat_out2in_10Ms.py index 48d3d199080..b3493641ea0 100644 --- a/src/plugins/nat/extras/nat_out2in_10Ms.py +++ b/src/plugins/nat/extras/nat_out2in_10Ms.py @@ -1,35 +1,39 @@ from trex_stl_lib.api import * -class STLS1: - def create_stream (self): - base_pkt = Ether()/IP(src="2.2.0.1")/UDP(sport=12) +class STLS1: + def create_stream(self): + base_pkt = Ether() / IP(src="2.2.0.1") / UDP(sport=12) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len vm = STLVM() - vm.tuple_var(name="tuple", ip_min="173.16.1.3", ip_max="173.17.135.162", port_min=1025, port_max=1124, limit_flows = 10000000) + vm.tuple_var( + name="tuple", + ip_min="173.16.1.3", + ip_max="173.17.135.162", + port_min=1025, + port_max=1124, + limit_flows=10000000, + ) vm.write(fv_name="tuple.ip", pkt_offset="IP.dst") vm.fix_chksum() vm.write(fv_name="tuple.port", pkt_offset="UDP.dport") - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) - def get_streams (self, direction = 0, **kwargs): + def get_streams(self, direction=0, **kwargs): return [self.create_stream()] # dynamic load - used for trex console or simulator def register(): return STLS1() - - - diff --git a/src/plugins/nat/extras/nat_out2in_10ks.py b/src/plugins/nat/extras/nat_out2in_10ks.py index e961504fcf9..abd82ce320d 100644 --- a/src/plugins/nat/extras/nat_out2in_10ks.py +++ b/src/plugins/nat/extras/nat_out2in_10ks.py @@ -1,35 +1,39 @@ from trex_stl_lib.api import * -class STLS1: - def create_stream (self): - base_pkt = Ether()/IP(src="2.2.0.1")/UDP(sport=12) +class STLS1: + def create_stream(self): + base_pkt = Ether() / IP(src="2.2.0.1") / UDP(sport=12) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len vm = STLVM() - vm.tuple_var(name="tuple", ip_min="173.16.1.3", ip_max="173.16.1.102", port_min=1025, port_max=1124, limit_flows = 100000) + vm.tuple_var( + name="tuple", + ip_min="173.16.1.3", + ip_max="173.16.1.102", + port_min=1025, + port_max=1124, + limit_flows=100000, + ) vm.write(fv_name="tuple.ip", pkt_offset="IP.dst") vm.fix_chksum() vm.write(fv_name="tuple.port", pkt_offset="UDP.dport") - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) - def get_streams (self, direction = 0, **kwargs): + def get_streams(self, direction=0, **kwargs): return [self.create_stream()] # dynamic load - used for trex console or simulator def register(): return STLS1() - - - diff --git a/src/plugins/nat/extras/nat_out2in_1Ms.py b/src/plugins/nat/extras/nat_out2in_1Ms.py index d2cb0810263..c08ef191e6c 100644 --- a/src/plugins/nat/extras/nat_out2in_1Ms.py +++ b/src/plugins/nat/extras/nat_out2in_1Ms.py @@ -1,35 +1,39 @@ from trex_stl_lib.api import * -class STLS1: - def create_stream (self): - base_pkt = Ether()/IP(src="2.2.0.1")/UDP(sport=12) +class STLS1: + def create_stream(self): + base_pkt = Ether() / IP(src="2.2.0.1") / UDP(sport=12) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len vm = STLVM() - vm.tuple_var(name="tuple", ip_min="173.16.1.3", ip_max="173.16.40.18", port_min=1025, port_max=1124, limit_flows = 1000000) + vm.tuple_var( + name="tuple", + ip_min="173.16.1.3", + ip_max="173.16.40.18", + port_min=1025, + port_max=1124, + limit_flows=1000000, + ) vm.write(fv_name="tuple.ip", pkt_offset="IP.dst") vm.fix_chksum() vm.write(fv_name="tuple.port", pkt_offset="UDP.dport") - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) - def get_streams (self, direction = 0, **kwargs): + def get_streams(self, direction=0, **kwargs): return [self.create_stream()] # dynamic load - used for trex console or simulator def register(): return STLS1() - - - diff --git a/src/plugins/nat/extras/nat_ses_open.py b/src/plugins/nat/extras/nat_ses_open.py index d614d4e7356..a267a6b67fb 100644 --- a/src/plugins/nat/extras/nat_ses_open.py +++ b/src/plugins/nat/extras/nat_ses_open.py @@ -1,44 +1,72 @@ from trex_stl_lib.api import * -class STLS1: - def __init__ (self): - self.ip_range = {'local': {'start': "10.0.0.3", 'end': "10.1.255.255"}, - 'external': {'start': "172.16.1.3", 'end': "172.16.1.3"}, - 'remote': {'start': "2.2.0.1", 'end': "2.2.0.1"}} - self.port_range = {'local': {'start': 1025, 'end': 65535}, - 'remote': {'start': 12, 'end': 12}} +class STLS1: + def __init__(self): + self.ip_range = { + "local": {"start": "10.0.0.3", "end": "10.1.255.255"}, + "external": {"start": "172.16.1.3", "end": "172.16.1.3"}, + "remote": {"start": "2.2.0.1", "end": "2.2.0.1"}, + } + self.port_range = { + "local": {"start": 1025, "end": 65535}, + "remote": {"start": 12, "end": 12}, + } - def create_stream (self, vm): - base_pkt = Ether()/IP()/UDP() + def create_stream(self, vm): + base_pkt = Ether() / IP() / UDP() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) pad = Padding() - pad.load = '\x00' * pad_len - base_pkt = base_pkt/pad - + pad.load = "\x00" * pad_len + base_pkt = base_pkt / pad + pkt = STLPktBuilder(pkt=base_pkt, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) - def get_streams (self, direction = 0, **kwargs): + def get_streams(self, direction=0, **kwargs): if direction == 0: - ip_src = self.ip_range['remote'] - ip_dst = self.ip_range['external'] - src_port = self.port_range['remote'] - dst_port = self.port_range['local'] + ip_src = self.ip_range["remote"] + ip_dst = self.ip_range["external"] + src_port = self.port_range["remote"] + dst_port = self.port_range["local"] else: - ip_src = self.ip_range['local'] - ip_dst = self.ip_range['remote'] - src_port = self.port_range['local'] - dst_port = self.port_range['remote'] + ip_src = self.ip_range["local"] + ip_dst = self.ip_range["remote"] + src_port = self.port_range["local"] + dst_port = self.port_range["remote"] vm = STLVM() - vm.var(name="ip_src", min_value=ip_src['start'], max_value=ip_src['end'], size=4, op="random") - vm.var(name="ip_dst", min_value=ip_dst['start'], max_value=ip_dst['end'], size=4, op="random") - vm.var(name="src_port", min_value=src_port['start'], max_value=src_port['end'], size=2, op="random") - vm.var(name="dst_port", min_value=dst_port['start'], max_value=dst_port['end'], size=2, op="random") + vm.var( + name="ip_src", + min_value=ip_src["start"], + max_value=ip_src["end"], + size=4, + op="random", + ) + vm.var( + name="ip_dst", + min_value=ip_dst["start"], + max_value=ip_dst["end"], + size=4, + op="random", + ) + vm.var( + name="src_port", + min_value=src_port["start"], + max_value=src_port["end"], + size=2, + op="random", + ) + vm.var( + name="dst_port", + min_value=dst_port["start"], + max_value=dst_port["end"], + size=2, + op="random", + ) vm.write(fv_name="ip_src", pkt_offset="IP.src") vm.write(fv_name="ip_dst", pkt_offset="IP.dst") @@ -47,12 +75,9 @@ class STLS1: vm.fix_chksum() - return [ self.create_stream(vm) ] + return [self.create_stream(vm)] # dynamic load - used for trex console or simulator def register(): return STLS1() - - - diff --git a/src/plugins/nat/extras/nat_static_gen_cfg.py b/src/plugins/nat/extras/nat_static_gen_cfg.py index 9e59bbfc0c2..009cf099582 100755 --- a/src/plugins/nat/extras/nat_static_gen_cfg.py +++ b/src/plugins/nat/extras/nat_static_gen_cfg.py @@ -2,24 +2,24 @@ import ipaddress import argparse -parser = argparse.ArgumentParser(description='Generate NAT plugin config.') -parser.add_argument('static_map_num', metavar='N', type=int, nargs=1, - help='number of static mappings') +parser = argparse.ArgumentParser(description="Generate NAT plugin config.") +parser.add_argument( + "static_map_num", metavar="N", type=int, nargs=1, help="number of static mappings" +) args = parser.parse_args() -file_name = 'nat_static_%s' % (args.static_map_num[0]) -outfile = open(file_name, 'w') +file_name = "nat_static_%s" % (args.static_map_num[0]) +outfile = open(file_name, "w") -outfile.write('set int ip address TenGigabitEthernet4/0/0 172.16.2.1/24\n') -outfile.write('set int ip address TenGigabitEthernet4/0/1 173.16.1.1/24\n') -outfile.write('set int state TenGigabitEthernet4/0/0 up\n') -outfile.write('set int state TenGigabitEthernet4/0/1 up\n') -outfile.write('ip route add 2.2.0.0/16 via 173.16.1.2 TenGigabitEthernet4/0/1\n') -outfile.write('ip route add 10.0.0.0/24 via 172.16.2.2 TenGigabitEthernet4/0/0\n') -outfile.write('set int nat44 in TenGigabitEthernet4/0/0 out TenGigabitEthernet4/0/1\n') - -for i in range (0, args.static_map_num[0]): - local = str(ipaddress.IPv4Address(u'10.0.0.3') + i) - external = str(ipaddress.IPv4Address(u'173.16.1.3') + i) - outfile.write('nat44 add static mapping local %s external %s\n' % (local, external)) +outfile.write("set int ip address TenGigabitEthernet4/0/0 172.16.2.1/24\n") +outfile.write("set int ip address TenGigabitEthernet4/0/1 173.16.1.1/24\n") +outfile.write("set int state TenGigabitEthernet4/0/0 up\n") +outfile.write("set int state TenGigabitEthernet4/0/1 up\n") +outfile.write("ip route add 2.2.0.0/16 via 173.16.1.2 TenGigabitEthernet4/0/1\n") +outfile.write("ip route add 10.0.0.0/24 via 172.16.2.2 TenGigabitEthernet4/0/0\n") +outfile.write("set int nat44 in TenGigabitEthernet4/0/0 out TenGigabitEthernet4/0/1\n") +for i in range(0, args.static_map_num[0]): + local = str(ipaddress.IPv4Address("10.0.0.3") + i) + external = str(ipaddress.IPv4Address("173.16.1.3") + i) + outfile.write("nat44 add static mapping local %s external %s\n" % (local, external)) diff --git a/src/plugins/nat/extras/nat_test_fast_path.py b/src/plugins/nat/extras/nat_test_fast_path.py index e869d40872a..fb880fb9e96 100644 --- a/src/plugins/nat/extras/nat_test_fast_path.py +++ b/src/plugins/nat/extras/nat_test_fast_path.py @@ -2,7 +2,6 @@ from trex_stl_lib.api import * class STLS1: - def create_stream(self): # base_pkt = Ether()/IP(dst="2.2.0.1")/UDP(dport=12) @@ -24,37 +23,46 @@ class STLS1: # return STLStream(packet=pkt, mode=STLTXCont()) - vm = STLScVmRaw([STLVmTupleGen(ip_min="10.0.0.1", ip_max="10.255.255.254", - port_min=1025, port_max=65535, - # name="stuple", limit_flows=10000), - name="stuple", limit_flows=100), - STLVmTupleGen(ip_min="2.0.0.1", ip_max="2.255.255.254", - port_min=1025, port_max=65535, - # name="dtuple", limit_flows=100000000), - name="dtuple", limit_flows=100), - - # write ip to packet IP.src - STLVmWrFlowVar(fv_name="stuple.ip", - pkt_offset="IP.src"), - STLVmWrFlowVar(fv_name="dtuple.ip", - pkt_offset="IP.dst"), - # fix checksum - STLVmFixIpv4(offset="IP"), - # write udp.port - STLVmWrFlowVar(fv_name="stuple.port", - pkt_offset="UDP.sport"), - STLVmWrFlowVar(fv_name="dtuple.port", - pkt_offset="UDP.dport"), - ] - ) - - base_pkt = Ether()/IP(src="16.0.0.1", dst="2.0.0.1")/UDP(dport=12, sport=1025) + vm = STLScVmRaw( + [ + STLVmTupleGen( + ip_min="10.0.0.1", + ip_max="10.255.255.254", + port_min=1025, + port_max=65535, + # name="stuple", limit_flows=10000), + name="stuple", + limit_flows=100, + ), + STLVmTupleGen( + ip_min="2.0.0.1", + ip_max="2.255.255.254", + port_min=1025, + port_max=65535, + # name="dtuple", limit_flows=100000000), + name="dtuple", + limit_flows=100, + ), + # write ip to packet IP.src + STLVmWrFlowVar(fv_name="stuple.ip", pkt_offset="IP.src"), + STLVmWrFlowVar(fv_name="dtuple.ip", pkt_offset="IP.dst"), + # fix checksum + STLVmFixIpv4(offset="IP"), + # write udp.port + STLVmWrFlowVar(fv_name="stuple.port", pkt_offset="UDP.sport"), + STLVmWrFlowVar(fv_name="dtuple.port", pkt_offset="UDP.dport"), + ] + ) + + base_pkt = ( + Ether() / IP(src="16.0.0.1", dst="2.0.0.1") / UDP(dport=12, sport=1025) + ) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) diff --git a/src/plugins/nat/extras/nat_test_slow_path.py b/src/plugins/nat/extras/nat_test_slow_path.py index a6351b98adf..3145a2c6a59 100644 --- a/src/plugins/nat/extras/nat_test_slow_path.py +++ b/src/plugins/nat/extras/nat_test_slow_path.py @@ -2,7 +2,6 @@ from trex_stl_lib.api import * class STLS1: - def create_stream(self): # base_pkt = Ether()/IP(dst="2.2.0.1")/UDP(dport=12) @@ -24,35 +23,44 @@ class STLS1: # return STLStream(packet=pkt, mode=STLTXCont()) - vm = STLScVmRaw([STLVmTupleGen(ip_min="10.0.0.1", ip_max="10.255.255.254", - port_min=1025, port_max=65535, - name="stuple", limit_flows=10000), - STLVmTupleGen(ip_min="2.0.0.1", ip_max="2.255.255.254", - port_min=1025, port_max=65535, - name="dtuple", limit_flows=100000000), - - # write ip to packet IP.src - STLVmWrFlowVar(fv_name="stuple.ip", - pkt_offset="IP.src"), - STLVmWrFlowVar(fv_name="dtuple.ip", - pkt_offset="IP.dst"), - # fix checksum - STLVmFixIpv4(offset="IP"), - # write udp.port - STLVmWrFlowVar(fv_name="stuple.port", - pkt_offset="UDP.sport"), - STLVmWrFlowVar(fv_name="dtuple.port", - pkt_offset="UDP.dport"), - ] - ) - - base_pkt = Ether()/IP(src="16.0.0.1", dst="2.0.0.1")/UDP(dport=12, sport=1025) + vm = STLScVmRaw( + [ + STLVmTupleGen( + ip_min="10.0.0.1", + ip_max="10.255.255.254", + port_min=1025, + port_max=65535, + name="stuple", + limit_flows=10000, + ), + STLVmTupleGen( + ip_min="2.0.0.1", + ip_max="2.255.255.254", + port_min=1025, + port_max=65535, + name="dtuple", + limit_flows=100000000, + ), + # write ip to packet IP.src + STLVmWrFlowVar(fv_name="stuple.ip", pkt_offset="IP.src"), + STLVmWrFlowVar(fv_name="dtuple.ip", pkt_offset="IP.dst"), + # fix checksum + STLVmFixIpv4(offset="IP"), + # write udp.port + STLVmWrFlowVar(fv_name="stuple.port", pkt_offset="UDP.sport"), + STLVmWrFlowVar(fv_name="dtuple.port", pkt_offset="UDP.dport"), + ] + ) + + base_pkt = ( + Ether() / IP(src="16.0.0.1", dst="2.0.0.1") / UDP(dport=12, sport=1025) + ) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) return STLStream(packet=pkt, mode=STLTXCont()) diff --git a/src/plugins/nat/extras/nat_test_slow_path_with_latency.py b/src/plugins/nat/extras/nat_test_slow_path_with_latency.py index 6c7663434c5..0c08e7a5e80 100644 --- a/src/plugins/nat/extras/nat_test_slow_path_with_latency.py +++ b/src/plugins/nat/extras/nat_test_slow_path_with_latency.py @@ -2,7 +2,6 @@ from trex_stl_lib.api import * class STLS1: - def create_stream(self, port_id): # base_pkt = Ether()/IP(dst="2.2.0.1")/UDP(dport=12) @@ -24,49 +23,61 @@ class STLS1: # return STLStream(packet=pkt, mode=STLTXCont()) - vm = STLScVmRaw([STLVmTupleGen(ip_min="10.0.0.1", ip_max="10.255.255.254", - port_min=1025, port_max=65535, - name="stuple", limit_flows=10000), - STLVmTupleGen(ip_min="2.0.0.1", ip_max="2.255.255.254", - port_min=1025, port_max=65535, - name="dtuple", limit_flows=100000000), - - # write ip to packet IP.src - STLVmWrFlowVar(fv_name="stuple.ip", - pkt_offset="IP.src"), - STLVmWrFlowVar(fv_name="dtuple.ip", - pkt_offset="IP.dst"), - # fix checksum - STLVmFixIpv4(offset="IP"), - # write udp.port - STLVmWrFlowVar(fv_name="stuple.port", - pkt_offset="UDP.sport"), - STLVmWrFlowVar(fv_name="dtuple.port", - pkt_offset="UDP.dport"), - ] - ) - - base_pkt = Ether()/IP(src="16.0.0.1", dst="2.0.0.1")/UDP(dport=12, sport=1025) + vm = STLScVmRaw( + [ + STLVmTupleGen( + ip_min="10.0.0.1", + ip_max="10.255.255.254", + port_min=1025, + port_max=65535, + name="stuple", + limit_flows=10000, + ), + STLVmTupleGen( + ip_min="2.0.0.1", + ip_max="2.255.255.254", + port_min=1025, + port_max=65535, + name="dtuple", + limit_flows=100000000, + ), + # write ip to packet IP.src + STLVmWrFlowVar(fv_name="stuple.ip", pkt_offset="IP.src"), + STLVmWrFlowVar(fv_name="dtuple.ip", pkt_offset="IP.dst"), + # fix checksum + STLVmFixIpv4(offset="IP"), + # write udp.port + STLVmWrFlowVar(fv_name="stuple.port", pkt_offset="UDP.sport"), + STLVmWrFlowVar(fv_name="dtuple.port", pkt_offset="UDP.dport"), + ] + ) + + base_pkt = ( + Ether() / IP(src="16.0.0.1", dst="2.0.0.1") / UDP(dport=12, sport=1025) + ) pad = Padding() if len(base_pkt) < 64: pad_len = 64 - len(base_pkt) - pad.load = '\x00' * pad_len + pad.load = "\x00" * pad_len - pad = max(0, 64 - len(base_pkt)) * 'x' - pad_latency = max(0, (64-4) - len(base_pkt)) * 'x' + pad = max(0, 64 - len(base_pkt)) * "x" + pad_latency = max(0, (64 - 4) - len(base_pkt)) * "x" - pkt = STLPktBuilder(pkt=base_pkt/pad, vm=vm) + pkt = STLPktBuilder(pkt=base_pkt / pad, vm=vm) - return [STLStream(packet=pkt, mode=STLTXCont()), - # latency stream - STLStream(packet = STLPktBuilder(pkt = base_pkt/pad_latency), - mode = STLTXCont(pps=1000), - flow_stats = STLFlowLatencyStats(pg_id = 12+port_id)) - ] + return [ + STLStream(packet=pkt, mode=STLTXCont()), + # latency stream + STLStream( + packet=STLPktBuilder(pkt=base_pkt / pad_latency), + mode=STLTXCont(pps=1000), + flow_stats=STLFlowLatencyStats(pg_id=12 + port_id), + ), + ] def get_streams(self, direction=0, **kwargs): # return [self.create_stream()] - return self.create_stream(kwargs['port_id']) + return self.create_stream(kwargs["port_id"]) # dynamic load - used for trex console or simulator diff --git a/src/plugins/nat/lib/alloc.h b/src/plugins/nat/lib/alloc.h index 0c302bf4cfb..882809e829c 100644 --- a/src/plugins/nat/lib/alloc.h +++ b/src/plugins/nat/lib/alloc.h @@ -42,14 +42,12 @@ struct nat_ip4_pool_addr_s { ip4_address_t addr; u32 fib_index; -/* *INDENT-OFF* */ #define _(N, i, n, s) \ u16 busy_##n##_ports; \ u16 * busy_##n##_ports_per_thread; \ uword * busy_##n##_port_bitmap; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ }; struct nat_ip4_addr_port_s diff --git a/src/plugins/nat/lib/inlines.h b/src/plugins/nat/lib/inlines.h index 46be64d36cf..24e3ba83a5b 100644 --- a/src/plugins/nat/lib/inlines.h +++ b/src/plugins/nat/lib/inlines.h @@ -20,20 +20,18 @@ #include <vnet/ip/icmp46_packet.h> -static_always_inline u8 +static_always_inline u64 icmp_type_is_error_message (u8 icmp_type) { - 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; + int bmp = 0; + bmp |= 1 << ICMP4_destination_unreachable; + bmp |= 1 << ICMP4_time_exceeded; + bmp |= 1 << ICMP4_parameter_problem; + bmp |= 1 << ICMP4_source_quench; + bmp |= 1 << ICMP4_redirect; + bmp |= 1 << ICMP4_alternate_host_address; + + return (1ULL << icmp_type) & bmp; } #endif /* included_nat_inlines_h__ */ diff --git a/src/plugins/nat/lib/ipfix_logging.c b/src/plugins/nat/lib/ipfix_logging.c index 27a0b92ae71..593fa09f7e2 100644 --- a/src/plugins/nat/lib/ipfix_logging.c +++ b/src/plugins/nat/lib/ipfix_logging.c @@ -143,12 +143,9 @@ do { \ * @returns template packet */ static inline u8 * -nat_template_rewrite (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port, - nat_event_t event, quota_exceed_event_t quota_event) +nat_template_rewrite (ipfix_exporter_t *exp, flow_report_t *fr, + u16 collector_port, nat_event_t event, + quota_exceed_event_t quota_event) { nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main; ip4_header_t *ip; @@ -164,7 +161,7 @@ nat_template_rewrite (flow_report_main_t * frm, flow_report_stream_t *stream; u32 stream_index; - stream = &frm->streams[fr->stream_index]; + stream = &exp->streams[fr->stream_index]; stream_index = clib_atomic_fetch_or(&silm->stream_index, 0); clib_atomic_cmp_and_swap (&silm->stream_index, @@ -241,8 +238,8 @@ nat_template_rewrite (flow_report_main_t * frm, ip->ip_version_and_header_length = 0x45; ip->ttl = 254; ip->protocol = IP_PROTOCOL_UDP; - ip->src_address.as_u32 = src_address->as_u32; - ip->dst_address.as_u32 = collector_address->as_u32; + ip->src_address.as_u32 = exp->src_address.ip.ip4.as_u32; + ip->dst_address.as_u32 = exp->ipfix_collector.ip.ip4.as_u32; udp->src_port = clib_host_to_net_u16 (stream->src_port); udp->dst_port = clib_host_to_net_u16 (collector_port); udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip)); @@ -390,97 +387,72 @@ nat_template_rewrite (flow_report_main_t * frm, } u8 * -nat_template_rewrite_addr_exhausted (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port, - ipfix_report_element_t *elts, - u32 n_elts, u32 *stream_index) +nat_template_rewrite_addr_exhausted (ipfix_exporter_t *exp, flow_report_t *fr, + u16 collector_port, + ipfix_report_element_t *elts, u32 n_elts, + u32 *stream_index) { - return nat_template_rewrite (frm, fr, collector_address, src_address, - collector_port, NAT_ADDRESSES_EXHAUTED, 0); + return nat_template_rewrite (exp, fr, collector_port, NAT_ADDRESSES_EXHAUTED, + 0); } u8 * -nat_template_rewrite_nat44_session (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port, - ipfix_report_element_t *elts, - u32 n_elts, u32 *stream_index) +nat_template_rewrite_nat44_session (ipfix_exporter_t *exp, flow_report_t *fr, + u16 collector_port, + ipfix_report_element_t *elts, u32 n_elts, + u32 *stream_index) { - return nat_template_rewrite (frm, fr, collector_address, src_address, - collector_port, NAT44_SESSION_CREATE, 0); + return nat_template_rewrite (exp, fr, collector_port, NAT44_SESSION_CREATE, + 0); } u8 * -nat_template_rewrite_max_entries_per_usr (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port, - ipfix_report_element_t *elts, - u32 n_elts, u32 *stream_index) +nat_template_rewrite_max_entries_per_usr ( + ipfix_exporter_t *exp, flow_report_t *fr, ip4_address_t *collector_address, + ip4_address_t *src_address, u16 collector_port, ipfix_report_element_t *elts, + u32 n_elts, u32 *stream_index) { - return nat_template_rewrite (frm, fr, collector_address, src_address, - collector_port, QUOTA_EXCEEDED, - MAX_ENTRIES_PER_USER); + return nat_template_rewrite (exp, fr, collector_port, QUOTA_EXCEEDED, + MAX_ENTRIES_PER_USER); } u8 * -nat_template_rewrite_max_sessions (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, +nat_template_rewrite_max_sessions (ipfix_exporter_t *exp, flow_report_t *fr, u16 collector_port, - ipfix_report_element_t *elts, - u32 n_elts, u32 *stream_index) + ipfix_report_element_t *elts, u32 n_elts, + u32 *stream_index) { - return nat_template_rewrite (frm, fr, collector_address, src_address, - collector_port, QUOTA_EXCEEDED, - MAX_SESSION_ENTRIES); + return nat_template_rewrite (exp, fr, collector_port, QUOTA_EXCEEDED, + MAX_SESSION_ENTRIES); } u8 * -nat_template_rewrite_max_bibs (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, +nat_template_rewrite_max_bibs (ipfix_exporter_t *exp, flow_report_t *fr, u16 collector_port, - ipfix_report_element_t *elts, - u32 n_elts, u32 *stream_index) + ipfix_report_element_t *elts, u32 n_elts, + u32 *stream_index) { - return nat_template_rewrite (frm, fr, collector_address, src_address, - collector_port, QUOTA_EXCEEDED, - MAX_BIB_ENTRIES); + return nat_template_rewrite (exp, fr, collector_port, QUOTA_EXCEEDED, + MAX_BIB_ENTRIES); } u8 * -nat_template_rewrite_nat64_bib (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port, - ipfix_report_element_t *elts, - u32 n_elts, u32 *stream_index) +nat_template_rewrite_nat64_bib (ipfix_exporter_t *exp, flow_report_t *fr, + u16 collector_port, + ipfix_report_element_t *elts, u32 n_elts, + u32 *stream_index) { - return nat_template_rewrite (frm, fr, collector_address, src_address, - collector_port, NAT64_BIB_CREATE, 0); + return nat_template_rewrite (exp, fr, collector_port, NAT64_BIB_CREATE, 0); } u8 * -nat_template_rewrite_nat64_session (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port, - ipfix_report_element_t *elts, - u32 n_elts, u32 *stream_index) +nat_template_rewrite_nat64_session (ipfix_exporter_t *exp, flow_report_t *fr, + u16 collector_port, + ipfix_report_element_t *elts, u32 n_elts, + u32 *stream_index) { - return nat_template_rewrite (frm, fr, collector_address, src_address, - collector_port, NAT64_SESSION_CREATE, 0); + return nat_template_rewrite (exp, fr, collector_port, NAT64_SESSION_CREATE, + 0); } static inline void @@ -497,16 +469,17 @@ nat_ipfix_header_create (flow_report_main_t * frm, ip4_header_t *ip; udp_header_t *udp; vlib_main_t *vm = vlib_get_main (); - + ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0); + stream_index = clib_atomic_fetch_or(&silm->stream_index, 0); - stream = &frm->streams[stream_index]; + stream = &exp->streams[stream_index]; b0->current_data = 0; b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) + sizeof (*s); b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_FLOW_REPORT); vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = exp->fib_index; tp = vlib_buffer_get_current (b0); ip = (ip4_header_t *) & tp->ip4; udp = (udp_header_t *) (ip + 1); @@ -517,10 +490,10 @@ nat_ipfix_header_create (flow_report_main_t * frm, ip->ttl = 254; ip->protocol = IP_PROTOCOL_UDP; ip->flags_and_fragment_offset = 0; - ip->src_address.as_u32 = frm->src_address.as_u32; - ip->dst_address.as_u32 = frm->ipfix_collector.as_u32; + ip->src_address.as_u32 = exp->src_address.ip.ip4.as_u32; + ip->dst_address.as_u32 = exp->ipfix_collector.ip.ip4.as_u32; udp->src_port = clib_host_to_net_u16 (stream->src_port); - udp->dst_port = clib_host_to_net_u16 (frm->collector_port); + udp->dst_port = clib_host_to_net_u16 (exp->collector_port); udp->checksum = 0; h->export_time = clib_host_to_net_u32 ((u32) @@ -545,6 +518,7 @@ nat_ipfix_send (flow_report_main_t *frm, vlib_frame_t *f, vlib_buffer_t *b0, ip4_header_t *ip; udp_header_t *udp; vlib_main_t *vm = vlib_get_main (); + ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0); tp = vlib_buffer_get_current (b0); ip = (ip4_header_t *) & tp->ip4; @@ -563,7 +537,7 @@ nat_ipfix_send (flow_report_main_t *frm, vlib_frame_t *f, vlib_buffer_t *b0, ip->checksum = ip4_header_checksum (ip); udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); - if (frm->udp_checksum) + if (exp->udp_checksum) { udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); if (udp->checksum == 0) @@ -591,6 +565,7 @@ nat_ipfix_logging_nat44_ses (u32 thread_index, u8 nat_event, u32 src_ip, u64 now; u16 template_id; u32 vrf_id; + ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0); now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); now += silm->milisecond_time_0; @@ -663,8 +638,8 @@ nat_ipfix_logging_nat44_ses (u32 thread_index, u8 nat_event, u32 src_ip, b0->current_length += NAT44_SESSION_CREATE_LEN; } - if (PREDICT_FALSE - (do_flush || (offset + NAT44_SESSION_CREATE_LEN) > frm->path_mtu)) + if (PREDICT_FALSE (do_flush || + (offset + NAT44_SESSION_CREATE_LEN) > exp->path_mtu)) { template_id = clib_atomic_fetch_or ( &silm->nat44_session_template_id, @@ -691,6 +666,7 @@ nat_ipfix_logging_addr_exhausted (u32 thread_index, u32 pool_id, int do_flush) u64 now; u8 nat_event = NAT_ADDRESSES_EXHAUTED; u16 template_id; + ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0); now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); now += silm->milisecond_time_0; @@ -746,8 +722,8 @@ nat_ipfix_logging_addr_exhausted (u32 thread_index, u32 pool_id, int do_flush) b0->current_length += NAT_ADDRESSES_EXHAUTED_LEN; } - if (PREDICT_FALSE - (do_flush || (offset + NAT_ADDRESSES_EXHAUTED_LEN) > frm->path_mtu)) + if (PREDICT_FALSE (do_flush || + (offset + NAT_ADDRESSES_EXHAUTED_LEN) > exp->path_mtu)) { template_id = clib_atomic_fetch_or ( &silm->addr_exhausted_template_id, @@ -776,6 +752,7 @@ nat_ipfix_logging_max_entries_per_usr (u32 thread_index, u8 nat_event = QUOTA_EXCEEDED; u32 quota_event = clib_host_to_net_u32 (MAX_ENTRIES_PER_USER); u16 template_id; + ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0); now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); now += silm->milisecond_time_0; @@ -838,8 +815,8 @@ nat_ipfix_logging_max_entries_per_usr (u32 thread_index, b0->current_length += MAX_ENTRIES_PER_USER_LEN; } - if (PREDICT_FALSE - (do_flush || (offset + MAX_ENTRIES_PER_USER_LEN) > frm->path_mtu)) + if (PREDICT_FALSE (do_flush || + (offset + MAX_ENTRIES_PER_USER_LEN) > exp->path_mtu)) { template_id = clib_atomic_fetch_or ( &silm->max_entries_per_user_template_id, @@ -867,6 +844,7 @@ nat_ipfix_logging_max_ses (u32 thread_index, u32 limit, int do_flush) u8 nat_event = QUOTA_EXCEEDED; u32 quota_event = clib_host_to_net_u32 (MAX_SESSION_ENTRIES); u16 template_id; + ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0); now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); now += silm->milisecond_time_0; @@ -926,8 +904,7 @@ nat_ipfix_logging_max_ses (u32 thread_index, u32 limit, int do_flush) b0->current_length += MAX_SESSIONS_LEN; } - if (PREDICT_FALSE - (do_flush || (offset + MAX_SESSIONS_LEN) > frm->path_mtu)) + if (PREDICT_FALSE (do_flush || (offset + MAX_SESSIONS_LEN) > exp->path_mtu)) { template_id = clib_atomic_fetch_or ( &silm->max_sessions_template_id, @@ -955,6 +932,7 @@ nat_ipfix_logging_max_bib (u32 thread_index, u32 limit, int do_flush) u8 nat_event = QUOTA_EXCEEDED; u32 quota_event = clib_host_to_net_u32 (MAX_BIB_ENTRIES); u16 template_id; + ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0); now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); now += silm->milisecond_time_0; @@ -1014,8 +992,7 @@ nat_ipfix_logging_max_bib (u32 thread_index, u32 limit, int do_flush) b0->current_length += MAX_BIBS_LEN; } - if (PREDICT_FALSE - (do_flush || (offset + MAX_BIBS_LEN) > frm->path_mtu)) + if (PREDICT_FALSE (do_flush || (offset + MAX_BIBS_LEN) > exp->path_mtu)) { template_id = clib_atomic_fetch_or ( &silm->max_bibs_template_id, @@ -1044,6 +1021,7 @@ nat_ipfix_logging_nat64_bibe (u32 thread_index, u8 nat_event, vlib_main_t *vm = vlib_get_main (); u64 now; u16 template_id; + ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0); now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); now += silm->milisecond_time_0; @@ -1115,8 +1093,7 @@ nat_ipfix_logging_nat64_bibe (u32 thread_index, u8 nat_event, b0->current_length += NAT64_BIB_LEN; } - if (PREDICT_FALSE - (do_flush || (offset + NAT64_BIB_LEN) > frm->path_mtu)) + if (PREDICT_FALSE (do_flush || (offset + NAT64_BIB_LEN) > exp->path_mtu)) { template_id = clib_atomic_fetch_or ( &silm->nat64_bib_template_id, @@ -1147,6 +1124,7 @@ nat_ipfix_logging_nat64_ses (u32 thread_index, u8 nat_event, vlib_main_t *vm = vlib_get_main (); u64 now; u16 template_id; + ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0); now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3); now += silm->milisecond_time_0; @@ -1230,8 +1208,7 @@ nat_ipfix_logging_nat64_ses (u32 thread_index, u8 nat_event, b0->current_length += NAT64_SES_LEN; } - if (PREDICT_FALSE - (do_flush || (offset + NAT64_SES_LEN) > frm->path_mtu)) + if (PREDICT_FALSE (do_flush || (offset + NAT64_SES_LEN) > exp->path_mtu)) { template_id = clib_atomic_fetch_or ( &silm->nat64_ses_template_id, @@ -1342,9 +1319,23 @@ nat_ipfix_logging_nat44_ses_delete (u32 thread_index, u32 src_ip, void nat_ipfix_logging_addresses_exhausted (u32 thread_index, u32 pool_id) { - //TODO: This event SHOULD be rate limited + nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main; + static f64 *last_sent = 0; + skip_if_disabled (); + /* TODO: make rate configurable, use 1pps so far */ + clib_spinlock_lock_if_init (&silm->addr_exhausted_lock); + f64 now = vlib_time_now (vlib_get_main ()); + vec_validate (last_sent, pool_id); + if (now < last_sent[pool_id] + 1.0) + { + clib_spinlock_unlock_if_init (&silm->addr_exhausted_lock); + return; + } + last_sent[pool_id] = now; + clib_spinlock_unlock_if_init (&silm->addr_exhausted_lock); + nat_ipfix_logging_addr_exhausted (thread_index, pool_id, 0); } @@ -1385,9 +1376,22 @@ deterministic_nat_data_callback void nat_ipfix_logging_max_sessions (u32 thread_index, u32 limit) { - //TODO: This event SHOULD be rate limited + nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main; + static f64 last_sent = 0; + skip_if_disabled (); + /* TODO: make rate configurable, use 1pps so far */ + clib_spinlock_lock_if_init (&silm->max_sessions_lock); + f64 now = vlib_time_now (vlib_get_main ()); + if (now < last_sent + 1.0) + { + clib_spinlock_unlock_if_init (&silm->max_sessions_lock); + return; + } + last_sent = now; + clib_spinlock_unlock_if_init (&silm->max_sessions_lock); + nat_ipfix_logging_max_ses (thread_index, limit, 0); } @@ -1400,9 +1404,22 @@ nat_ipfix_logging_max_sessions (u32 thread_index, u32 limit) void nat_ipfix_logging_max_bibs (u32 thread_index, u32 limit) { - //TODO: This event SHOULD be rate limited + nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main; + static f64 last_sent = 0; + skip_if_disabled (); + /* TODO: make rate configurable, use 1pps so far */ + clib_spinlock_lock_if_init (&silm->max_bibs_lock); + f64 now = vlib_time_now (vlib_get_main ()); + if (now < last_sent + 1.0) + { + clib_spinlock_unlock_if_init (&silm->max_bibs_lock); + return; + } + last_sent = now; + clib_spinlock_unlock_if_init (&silm->max_bibs_lock); + nat_ipfix_logging_max_bib (thread_index, limit, 0); } @@ -1473,12 +1490,13 @@ nat_ipfix_logging_nat64_session (u32 thread_index, } vlib_frame_t * -data_callback (flow_report_main_t * frm, flow_report_t * fr, - vlib_frame_t * f, u32 * to_next, u32 node_index) +data_callback (flow_report_main_t *frm, ipfix_exporter_t *exp, + flow_report_t *fr, vlib_frame_t *f, u32 *to_next, + u32 node_index) { nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main; - if (PREDICT_FALSE (++silm->call_counter >= vec_len (frm->reports))) + if (PREDICT_FALSE (++silm->call_counter >= vec_len (exp->reports))) { nat_ipfix_flush_from_main(); silm->call_counter = 0; @@ -1500,7 +1518,7 @@ int nat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port) { nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main; - flow_report_main_t *frm = &flow_report_main; + ipfix_exporter_t *exp = &flow_report_main.exporters[0]; vnet_flow_report_add_del_args_t a; int rv; u8 e = enable ? 1 : 0; @@ -1515,7 +1533,7 @@ nat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port) a.flow_data_callback = data_callback; a.rewrite_callback = nat_template_rewrite_nat44_session; - rv = vnet_flow_report_add_del (frm, &a, NULL); + rv = vnet_flow_report_add_del (exp, &a, NULL); if (rv) { //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv); @@ -1523,7 +1541,7 @@ nat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port) } a.rewrite_callback = nat_template_rewrite_addr_exhausted; - rv = vnet_flow_report_add_del (frm, &a, NULL); + rv = vnet_flow_report_add_del (exp, &a, NULL); if (rv) { //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv); @@ -1531,7 +1549,7 @@ nat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port) } a.rewrite_callback = nat_template_rewrite_max_sessions; - rv = vnet_flow_report_add_del (frm, &a, NULL); + rv = vnet_flow_report_add_del (exp, &a, NULL); if (rv) { //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv); @@ -1539,7 +1557,7 @@ nat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port) } a.rewrite_callback = nat_template_rewrite_max_bibs; - rv = vnet_flow_report_add_del (frm, &a, NULL); + rv = vnet_flow_report_add_del (exp, &a, NULL); if (rv) { //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv); @@ -1547,7 +1565,7 @@ nat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port) } a.rewrite_callback = nat_template_rewrite_nat64_bib; - rv = vnet_flow_report_add_del (frm, &a, NULL); + rv = vnet_flow_report_add_del (exp, &a, NULL); if (rv) { //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv); @@ -1555,7 +1573,7 @@ nat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port) } a.rewrite_callback = nat_template_rewrite_nat64_session; - rv = vnet_flow_report_add_del (frm, &a, NULL); + rv = vnet_flow_report_add_del (exp, &a, NULL); if (rv) { //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv); @@ -1565,7 +1583,7 @@ nat_ipfix_logging_enable_disable (int enable, u32 domain_id, u16 src_port) // if endpoint dependent per user max entries is also required /* a.rewrite_callback = nat_template_rewrite_max_entries_per_usr; - rv = vnet_flow_report_add_del (frm, &a, NULL); + rv = vnet_flow_report_add_del (exp, &a, NULL); if (rv) { //nat_elog_warn_X1 ("vnet_flow_report_add_del returned %d", "i4", rv); @@ -1596,6 +1614,11 @@ nat_ipfix_logging_init (vlib_main_t * vm) silm->milisecond_time_0 = unix_time_now_nsec () * 1e-6; vec_validate (silm->per_thread_data, tm->n_vlib_mains - 1); + + /* Set up rate-limit */ + clib_spinlock_init (&silm->addr_exhausted_lock); + clib_spinlock_init (&silm->max_sessions_lock); + clib_spinlock_init (&silm->max_bibs_lock); } static uword @@ -1607,11 +1630,9 @@ ipfix_flush_process (vlib_main_t *vm, return 0; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat_ipfix_flush_node) = { .function = ipfix_flush_process, .name = "nat-ipfix-flush", .type = VLIB_NODE_TYPE_INPUT, .state = VLIB_NODE_STATE_INTERRUPT, }; -/* *INDENT-ON* */ diff --git a/src/plugins/nat/lib/ipfix_logging.h b/src/plugins/nat/lib/ipfix_logging.h index 0b8f568e1b1..dc7927a160c 100644 --- a/src/plugins/nat/lib/ipfix_logging.h +++ b/src/plugins/nat/lib/ipfix_logging.h @@ -108,6 +108,10 @@ typedef struct { /** nat data callbacks call counter */ u16 call_counter; + /** rate-limit locks */ + clib_spinlock_t addr_exhausted_lock; + clib_spinlock_t max_sessions_lock; + clib_spinlock_t max_bibs_lock; } nat_ipfix_logging_main_t; extern nat_ipfix_logging_main_t nat_ipfix_logging_main; diff --git a/src/plugins/nat/lib/lib.h b/src/plugins/nat/lib/lib.h index cea9ed71c8c..dc2c43beaaf 100644 --- a/src/plugins/nat/lib/lib.h +++ b/src/plugins/nat/lib/lib.h @@ -21,6 +21,17 @@ #include <vlibapi/api.h> +typedef struct +{ + u16 identifier; + u16 sequence; +} nat_icmp_echo_header_t; + +typedef struct +{ + u16 src_port, dst_port; +} nat_tcp_udp_header_t; + /* NAT API Configuration flags */ #define foreach_nat_config_flag \ _(0x01, IS_TWICE_NAT) \ diff --git a/src/plugins/nat/lib/log.h b/src/plugins/nat/lib/log.h index 26bd93f2589..a82028ed8bf 100644 --- a/src/plugins/nat/lib/log.h +++ b/src/plugins/nat/lib/log.h @@ -21,20 +21,7 @@ #include <vppinfra/elog.h> -#define foreach_nat_log_level \ - _ (0x00, LOG_NONE) \ - _ (0x01, LOG_ERROR) \ - _ (0x02, LOG_WARNING) \ - _ (0x03, LOG_NOTICE) \ - _ (0x04, LOG_INFO) \ - _ (0x05, LOG_DEBUG) - -typedef enum nat_log_level_t_ -{ -#define _(n, f) NAT_##f = n, - foreach_nat_log_level -#undef _ -} nat_log_level_t; +#include <nat/lib/nat_types.api_types.h> #define nat_elog(_pm, _level, _str) \ do \ diff --git a/src/plugins/nat/lib/nat_proto.h b/src/plugins/nat/lib/nat_proto.h index 9b20d9a71d1..4b57b994e22 100644 --- a/src/plugins/nat/lib/nat_proto.h +++ b/src/plugins/nat/lib/nat_proto.h @@ -28,6 +28,7 @@ typedef enum #define _(N, i, n, s) NAT_PROTOCOL_##N = i, foreach_nat_protocol #undef _ + NAT_N_PROTOCOLS } nat_protocol_t; always_inline nat_protocol_t diff --git a/src/plugins/nat/nat44-ed/nat44_ed.api b/src/plugins/nat/nat44-ed/nat44_ed.api index 36637b26246..322260f7f96 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed.api +++ b/src/plugins/nat/nat44-ed/nat44_ed.api @@ -13,13 +13,13 @@ * limitations under the License. */ -option version = "5.4.0"; +option version = "5.5.0"; import "vnet/ip/ip_types.api"; import "vnet/interface_types.api"; import "plugins/nat/lib/nat_types.api"; /** - * @file nat44.api + * @file nat44_ed.api * @brief VPP control-plane API messages. * * This file defines VPP control-plane API messages which are generally @@ -35,41 +35,6 @@ enum nat44_config_flags : u8 NAT44_IS_OUT2IN_DPO = 0x08, }; -/** \brief Enable/disable NAT44 plugin - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param inside_vrf - inside vrf id - @param outside_vrf - outside vrf id - @param users - maximum number of users per thread - (NAT44_IS_ENDPOINT_INDEPENDENT) - @param user_memory - overwrite hash allocation parameter - (NAT44_IS_ENDPOINT_INDEPENDENT) - @param sessions - maximum number of sessions per thread - @param session_memory - overwrite hash allocation parameter - @param user_sessions - maximum number of sessions per user - (NAT44_IS_ENDPOINT_INDEPENDENT) - @param enable - true if enable, false if disable - @param flags - flag NAT44_IS_ENDPOINT_INDEPENDENT, - NAT44_IS_ENDPOINT_DEPENDENT, - NAT44_IS_STATIC_MAPPING_ONLY, - NAT44_IS_CONNECTION_TRACKING, - NAT44_IS_OUT2IN_DPO -*/ -autoreply define nat44_plugin_enable_disable { - option deprecated; - u32 client_index; - u32 context; - u32 inside_vrf; - u32 outside_vrf; - u32 users; - u32 user_memory; - u32 sessions; - u32 session_memory; - u32 user_sessions; - bool enable; - vl_api_nat44_config_flags_t flags; -}; - /** \brief Enable/disable NAT44ED plugin @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -82,7 +47,6 @@ autoreply define nat44_plugin_enable_disable { NAT44_IS_CONNECTION_TRACKING */ autoreply define nat44_ed_plugin_enable_disable { - option in_progress; u32 client_index; u32 context; u32 inside_vrf; @@ -93,146 +57,65 @@ autoreply define nat44_ed_plugin_enable_disable { vl_api_nat44_config_flags_t flags; }; -/** \brief Control ping from client to api server request +/** \brief Enable/disable forwarding for NAT44 + Forward packets which don't match existing translation + or static mapping instead of dropping them. @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request + @param enable - true for enable, false for disable */ -define nat_control_ping -{ +autoreply define nat44_forwarding_enable_disable { option deprecated; u32 client_index; u32 context; + bool enable; }; -/** \brief Control ping from the client to the server response +/** \brief Enable/disable NAT IPFIX logging @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param vpe_pid - the pid of the vpe, returned by the server + @param domain_id - observation domain ID + @param src_port - source port number + @param enable - true if enable, false if disable */ -define nat_control_ping_reply -{ +autoreply define nat_ipfix_enable_disable { option deprecated; - u32 context; - i32 retval; u32 client_index; - u32 vpe_pid; + u32 context; + u32 domain_id; + u16 src_port; + bool enable; }; -/** \brief Show NAT plugin startup config +/** \brief Set values of timeouts for NAT sessions (seconds) @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request + @param udp - UDP timeout (default 300sec) + @param tcp_established - TCP established timeout (default 7440sec) + @param tcp_transitory - TCP transitory timeout (default 240sec) + @param icmp - ICMP timeout (default 60sec) */ -define nat_show_config -{ +autoreply define nat_set_timeouts { option deprecated; u32 client_index; u32 context; + u32 udp; + u32 tcp_established; + u32 tcp_transitory; + u32 icmp; }; -/** \brief DEPRECATED: Show NAT plugin startup config reply - @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param static_mapping_only - if true dynamic translations disabled - @param static_mapping_connection_tracking - if true create session data - @param deterministic - if true deterministic mapping - @param endpoint_dependent - if true endpoint-dependent mode - @param out2in_dpo - if true out2in dpo mode - @param dslite_ce - if true DS-Lite is CE/B4 element, if false AFTR elemet - @param translation_buckets - number of translation hash buckets - @param translation_memory_size - translation hash memory size - @param user_buckets - number of user hash buckets - @param user_memory_size - user hash memory size - @param max_translations_per_user - maximum number of translations per user - @param outside_vrf_id - outside VRF id - @param inside_vrf_id - default inside VRF id - @param nat64_bib_buckets - number of NAT64 BIB hash buckets - @param nat64_bib_memory_size - memory size of NAT64 BIB hash - @param nat64_st_buckets - number of NAT64 session table hash buckets - @param nat64_st_memory_size - memory size of NAT64 session table hash -*/ -define nat_show_config_reply -{ - option deprecated; - u32 context; - i32 retval; - bool static_mapping_only; - bool static_mapping_connection_tracking; - bool deterministic; - bool endpoint_dependent; - bool out2in_dpo; - bool dslite_ce; - u32 translation_buckets; - u32 translation_memory_size; - u32 user_buckets; - u64 user_memory_size; - u32 max_translations_per_user; - u32 outside_vrf_id; - u32 inside_vrf_id; - u32 nat64_bib_buckets; - u64 nat64_bib_memory_size; - u32 nat64_st_buckets; - u64 nat64_st_memory_size; -}; - -/** \brief Show NAT plugin startup config +/** \brief NAT44 set session limit @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request + @param session_limit - session limit + @param vrf_id - vrf id */ -define nat_show_config_2 -{ - option deprecated; +autoreply define nat44_set_session_limit { u32 client_index; u32 context; -}; - -/** \brief Show NAT plugin startup config reply - @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param static_mapping_only - if true dynamic translations disabled - @param static_mapping_connection_tracking - if true create session data - @param deterministic - if true deterministic mapping - @param endpoint_dependent - if true endpoint-dependent mode - @param out2in_dpo - if true out2in dpo mode - @param dslite_ce - if true DS-Lite is CE/B4 element, if false AFTR elemet - @param translation_buckets - number of translation hash buckets - @param translation_memory_size - translation hash memory size - @param user_buckets - number of user hash buckets - @param user_memory_size - user hash memory size - @param max_translations_per_user - maximum number of translations per user - @param outside_vrf_id - outside VRF id - @param inside_vrf_id - default inside VRF id - @param nat64_bib_buckets - number of NAT64 BIB hash buckets - @param nat64_bib_memory_size - memory size of NAT64 BIB hash - @param nat64_st_buckets - number of NAT64 session table hash buckets - @param nat64_st_memory_size - memory size of NAT64 session table hash - @param max_translations_per_thread - max translations per worker thread - @param max_users_per_thread - max users per worker thread -*/ -define nat_show_config_2_reply -{ - option deprecated; - u32 context; - i32 retval; - bool static_mapping_only; - bool static_mapping_connection_tracking; - bool deterministic; - bool endpoint_dependent; - bool out2in_dpo; - bool dslite_ce; - u32 translation_buckets; - u64 translation_memory_size; - u32 user_buckets; - u64 user_memory_size; - u32 max_translations_per_user; - u32 outside_vrf_id; - u32 inside_vrf_id; - u32 nat64_bib_buckets; - u64 nat64_bib_memory_size; - u32 nat64_st_buckets; - u64 nat64_st_memory_size; - u32 max_translations_per_thread; - u32 max_users_per_thread; + u32 session_limit; + u32 vrf_id; }; /** \brief Show NAT44 plugin running config @@ -241,7 +124,6 @@ define nat_show_config_2_reply */ define nat44_show_running_config { - option in_progress; u32 client_index; u32 context; }; @@ -267,7 +149,6 @@ define nat44_show_running_config */ define nat44_show_running_config_reply { - option in_progress; u32 context; i32 retval; u32 inside_vrf; @@ -284,41 +165,6 @@ define nat44_show_running_config_reply vl_api_nat44_config_flags_t flags; }; -/** \brief Run nat44 garbage collection - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -autoreply define nat44_session_cleanup { - option deprecated; - u32 client_index; - u32 context; -}; - -/** \brief NAT44 set session limit - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param session_limit - session limit - @param vrf_id - vrf id -*/ -autoreply define nat44_set_session_limit { - u32 client_index; - u32 context; - u32 session_limit; - u32 vrf_id; -}; - -/** \brief Set NAT logging level - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param log_level - logging level -*/ -autoreply define nat_set_log_level { - option deprecated; - u32 client_index; - u32 context; - vl_api_nat_log_level_t log_level; -}; - /** \brief Set NAT workers @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -352,121 +198,82 @@ define nat_worker_details { string name[64]; }; -/** \brief Enable/disable NAT IPFIX logging +/** \brief Add/delete inter VRF NAT44-ED routing table @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request - @param domain_id - observation domain ID - @param src_port - source port number - @param enable - true if enable, false if disable + @param table_vrf_id - id of (rx) VRF used for resolving + destination (tx) VRF during dynamic + session creation + @param is_add - if true add else del */ -autoreply define nat_ipfix_enable_disable { - option deprecated; +autoreply define nat44_ed_add_del_vrf_table { u32 client_index; u32 context; - u32 domain_id; - u16 src_port; - bool enable; + u32 table_vrf_id; + bool is_add; }; -/** \brief Set values of timeouts for NAT sessions (seconds) +/** \brief Add/del inter VRF NAT44-ED route record @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request - @param udp - UDP timeout (default 300sec) - @param tcp_established - TCP established timeout (default 7440sec) - @param tcp_transitory - TCP transitory timeout (default 240sec) - @param icmp - ICMP timeout (default 60sec) + @param table_vrf_id - id of the VRF NAT routing table + @param vrf_id - id of resolving destination (tx) VRF table + @param is_add - if true add else del */ -autoreply define nat_set_timeouts { - option deprecated; +autoreply define nat44_ed_add_del_vrf_route { u32 client_index; u32 context; - u32 udp; - u32 tcp_established; - u32 tcp_transitory; - u32 icmp; + u32 table_vrf_id; + u32 vrf_id; + bool is_add; }; -/** \brief Get values of timeouts for NAT sessions (seconds) +/** \brief Dump NAT44-ED inter VRF NAT routing tables @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request */ -define nat_get_timeouts { - option deprecated; +define nat44_ed_vrf_tables_dump { u32 client_index; u32 context; -}; - -/** \brief Get values of timeouts for NAT sessions reply - @param context - sender context, to match reply w/ request - @param retval - return code - @param udp - UDP timeout - @param tcp_established - TCP established timeout - @param tcp_transitory - TCP transitory timeout - @param icmp - ICMP timeout -*/ -define nat_get_timeouts_reply { option deprecated; - u32 context; - i32 retval; - u32 udp; - u32 tcp_established; - u32 tcp_transitory; - u32 icmp; }; -/** \brief Set address and port assignment algorithm - @param client_index - opaque cookie to identify the sender +/** \brief NAT44-ED inter VRF NAT routing table details response @param context - sender context, to match reply w/ request - @param alg - address and port assignment algorithm: - 0 - default, 1 - MAP-E, 2 - port range - (see nat_addr_and_port_alloc_alg_t in nat.h) - @param psid_offset - number of offset bits (valid only for MAP-E alg) - @param psid_length - length of PSID (valid only for MAP-E alg) - @param psid - Port Set Identifier (PSID) value (valid only for MAP-E alg) - @param start_port - beginning of the port range - @param end_port - end of the port range + @param table_vrf_id - id of the VRF NAT routing table + @param n_vrf_ids - number of vrf_ids + @param vrf_ids - ids of resolving destination (tx) VRFs */ -autoreply define nat_set_addr_and_port_alloc_alg { - u32 client_index; +define nat44_ed_vrf_tables_details { u32 context; - u8 alg; - u8 psid_offset; - u8 psid_length; - u16 psid; - u16 start_port; - u16 end_port; + u32 table_vrf_id; + u32 n_vrf_ids; + u32 vrf_ids[n_vrf_ids]; + option deprecated; }; -/** \brief Get address and port assignment algorithm +/** \brief Dump NAT44-ED inter VRF NAT routing tables @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request */ -define nat_get_addr_and_port_alloc_alg { +define nat44_ed_vrf_tables_v2_dump { u32 client_index; u32 context; + option status="in_progress"; }; -/** \brief Get address and port assignment algorithm reply +/** \brief NAT44-ED inter VRF NAT routing table details response @param context - sender context, to match reply w/ request - @param retval - return code - @param alg - address and port assignment algorithm: - 0 - default, 1 - MAP-E, 2 - port range - (see nat_addr_and_port_alloc_alg_t in nat.h) - @param psid_offset - number of offset bits (valid only for MAP-E alg) - @param psid_length - length of PSID (valid only for MAP-E alg) - @param psid - Port Set Identifier (PSID) value (valid only for MAP-E alg) - @param start_port - beginning of the port range - @param end_port - end of the port range + @param table_vrf_id - id of the VRF NAT routing table + @param n_vrf_ids - number of vrf_ids + @param vrf_ids - ids of resolving destination (tx) VRFs */ -define nat_get_addr_and_port_alloc_alg_reply { +define nat44_ed_vrf_tables_v2_details { u32 context; - i32 retval; - u8 alg; - u8 psid_offset; - u8 psid_length; - u16 psid; - u16 start_port; - u16 end_port; + u32 table_vrf_id; + u32 n_vrf_ids; + u32 vrf_ids[n_vrf_ids]; + option status="in_progress"; }; /** \brief Set TCP MSS rewriting configuration @@ -504,138 +311,73 @@ define nat_get_mss_clamping_reply { bool enable; }; -/** \brief Set HA listener (local settings) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param ip_address - local IP4 address - @param port - local UDP port number - @param path_mtu - path MTU between local and failover -*/ -autoreply define nat_ha_set_listener { - u32 client_index; - u32 context; - vl_api_ip4_address_t ip_address; - u16 port; - u32 path_mtu; -}; - -/** \brief Set HA failover (remote settings) +/** \brief Set NAT handoff frame queue options @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request - @param ip_address - failover IP4 address - @param port - failvoer UDP port number - @param session_refresh_interval - number of seconds after which to send - session counters refresh + @param frame_queue_nelts - number of worker handoff frame queue elements */ -autoreply define nat_ha_set_failover { +autoreply define nat44_ed_set_fq_options { u32 client_index; u32 context; - vl_api_ip4_address_t ip_address; - u16 port; - u32 session_refresh_interval; + u32 frame_queue_nelts; }; -/** \brief Get HA listener/local configuration +/** \brief Show NAT handoff frame queue options @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request */ -define nat_ha_get_listener { +define nat44_ed_show_fq_options +{ u32 client_index; u32 context; }; -/** \brief Get HA listener/local configuration reply +/** \brief Show NAT handoff frame queue options reply @param context - sender context, to match reply w/ request - @param retval - return code - @param ip_address - local IP4 address - @param port - local UDP port number - @param path_mtu - Path MTU between local and failover + @param retval - return code for the request + @param frame_queue_nelts - number of worker handoff frame queue elements */ -define nat_ha_get_listener_reply { +define nat44_ed_show_fq_options_reply +{ u32 context; i32 retval; - vl_api_ip4_address_t ip_address; - u16 port; - u32 path_mtu; + u32 frame_queue_nelts; }; -/** \brief Get HA failover/remote settings +/** \brief Add/delete NAT44 pool address from specific interfce @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request + @param is_add - true if add, false if delete + @param sw_if_index - software index of the interface + @param flags - flag NAT_TWICE_NAT if NAT address range for external hosts */ -define nat_ha_get_failover { +autoreply define nat44_add_del_interface_addr { u32 client_index; u32 context; + bool is_add; + vl_api_interface_index_t sw_if_index; + vl_api_nat_config_flags_t flags; }; -/** \brief Get HA failover/remote settings reply - @param context - sender context, to match reply w/ request - @param retval - return code - @param ip_address - failover IP4 address - @param port - failvoer UDP port number - @param session_refresh_interval - number of seconds after which to send - session counters refresh -*/ -define nat_ha_get_failover_reply { - u32 context; - i32 retval; - vl_api_ip4_address_t ip_address; - u16 port; - u32 session_refresh_interval; -}; - -/** \brief Flush the current HA data (for testing) +/** \brief Dump NAT44 pool addresses interfaces @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request */ -autoreply define nat_ha_flush { +define nat44_interface_addr_dump { u32 client_index; u32 context; }; -/** \brief Resync HA (resend existing sessions to new failover) - @param client_index - opaque cookie to identify the sender +/** \brief NAT44 pool addresses interfaces details response @param context - sender context, to match reply w/ request - @param want_resync_event - resync completed event sent to the sender via - nat_ha_resync_completed_event API message if - non-zero - @param pid - sender's pid -*/ -autoreply define nat_ha_resync -{ - u32 client_index; - u32 context; - u8 want_resync_event; - u32 pid; -}; - -/** \brief Tell client about a HA resync completion event - @param client_index - opaque cookie to identify the sender - @param pid - client pid registered to receive notification - @param missed_count - number of missed (not ACKed) messages -*/ -define nat_ha_resync_completed_event -{ - u32 client_index; - u32 pid; - u32 missed_count; -}; - -service { - rpc nat_ha_resync returns nat_ha_resync_reply events nat_ha_resync_completed_event; -}; + @param sw_if_index - software index of the interface + @param flags - flag NAT_TWICE_NAT if NAT address range for external hosts -/** \brief Del NAT44 user - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param ip_address - IPv4 address - @param fib_index - FIB index */ -autoreply define nat44_del_user { - u32 client_index; +define nat44_interface_addr_details { u32 context; - vl_api_ip4_address_t ip_address; - u32 fib_index; + vl_api_interface_index_t sw_if_index; + vl_api_nat_config_flags_t flags; }; /** \brief Add/del NAT44 address range @@ -719,47 +461,6 @@ define nat44_interface_details { vl_api_interface_index_t sw_if_index; }; -/** \brief Enable/disbale NAT44 as an interface output feature (postrouting - in2out translation) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - true if add, false if delete - @param flags - flag NAT_IS_INSIDE if interface is inside else - interface is outside - @param sw_if_index - software index of the interface -*/ -autoreply define nat44_interface_add_del_output_feature { - option deprecated; - u32 client_index; - u32 context; - bool is_add; - vl_api_nat_config_flags_t flags; - vl_api_interface_index_t sw_if_index; -}; - -/** \brief Dump interfaces with NAT44 output feature - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define nat44_interface_output_feature_dump { - option deprecated; - u32 client_index; - u32 context; -}; - -/** \brief NAT44 interface with output feature details response - @param context - sender context, to match reply w/ request - @param flags - flag NAT_IS_INSIDE if interface is inside else - interface is outside - @param sw_if_index - software index of the interface -*/ -define nat44_interface_output_feature_details { - option deprecated; - u32 context; - vl_api_nat_config_flags_t flags; - vl_api_interface_index_t sw_if_index; -}; - /** \brief add/del NAT output interface (postrouting in2out translation) @param client_index - opaque cookie to identify the sender @@ -821,6 +522,8 @@ define nat44_ed_output_interface_details @param tag - opaque string tag */ autoreply define nat44_add_del_static_mapping { + option deprecated; + u32 client_index; u32 context; bool is_add; @@ -859,7 +562,6 @@ autoreply define nat44_add_del_static_mapping { @param tag - opaque string tag */ autoreply define nat44_add_del_static_mapping_v2 { - option in_progress; u32 client_index; u32 context; bool is_add; @@ -971,40 +673,131 @@ define nat44_identity_mapping_details { string tag[64]; }; -/** \brief Add/delete NAT44 pool address from specific interfce +/** \brief NAT44 load-balancing address and port pair + @param addr - IPv4 address of the internal node + @param port - L4 port number of the internal node + @param probability - probability of the internal node to be randomly matched + @param vrf_id - VRF id +*/ +typedef nat44_lb_addr_port { + vl_api_ip4_address_t addr; + u16 port; + u8 probability; + u32 vrf_id; +}; + +/** \brief Add/delete NAT44 load-balancing static mapping rule @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_add - true if add, false if delete - @param sw_if_index - software index of the interface - @param flags - flag NAT_TWICE_NAT if NAT address range for external hosts + @param flags - flag NAT_TWICE_NAT if NAT address range for external hosts, + flag NAT_SELF_TWICE_NAT if translate external host address + and port whenever external host address equals local + address of internal host, + flag NAT_OUT2IN_ONLY if rule match only out2in direction + @param external_addr - external IPv4 address of the service + @param external_port - external L4 port number of the service + @param protocol - IP protocol number of the service + @param affinity - if 0 disabled, otherwise client IP affinity sticky time + in seconds + @param local_num - number of local network nodes + @param locals - local network nodes + @param tag - opaque string tag */ -autoreply define nat44_add_del_interface_addr { +autoreply define nat44_add_del_lb_static_mapping { u32 client_index; u32 context; bool is_add; - vl_api_interface_index_t sw_if_index; vl_api_nat_config_flags_t flags; + vl_api_ip4_address_t external_addr; + u16 external_port; + u8 protocol; + u32 affinity; + string tag[64]; + u32 local_num; + vl_api_nat44_lb_addr_port_t locals[local_num]; }; -/** \brief Dump NAT44 pool addresses interfaces +/** \brief Add/delete NAT44 load-balancing static mapping rule backend @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request + @param is_add - true if add, false if delete + @param external_addr - external IPv4 address of the service + @param external_port - external L4 port number of the service + @param protocol - IP protocol number of the service + @param local - local network node */ -define nat44_interface_addr_dump { +autoreply define nat44_lb_static_mapping_add_del_local { u32 client_index; u32 context; + bool is_add; + vl_api_ip4_address_t external_addr; + u16 external_port; + u8 protocol; + vl_api_nat44_lb_addr_port_t local; }; -/** \brief NAT44 pool addresses interfaces details response +/** \brief Dump NAT44 load-balancing static mapping rules + @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request - @param sw_if_index - software index of the interface - @param flags - flag NAT_TWICE_NAT if NAT address range for external hosts +*/ +define nat44_lb_static_mapping_dump { + u32 client_index; + u32 context; +}; +/** \brief NAT44 load-balancing static mapping rule details response + @param context - sender context, to match reply w/ request + @param external_addr - external IPv4 address of the service + @param external_port - external L4 port number of the service + @param protocol - IP protocol number of the service + @param flags - flag NAT_TWICE_NAT if NAT address range for external hosts, + flag NAT_SELF_TWICE_NAT if translate external host address + and port whenever external host address equals local + address of internal host, + flag NAT_OUT2IN_ONLY if rule match only out2in direction + @param affinity - if 0 disabled, otherwise client IP affinity sticky time + in seconds + @param local_num - number of local network nodes + @param locals - local network nodes + @param tag - opaque string tag */ -define nat44_interface_addr_details { +define nat44_lb_static_mapping_details { u32 context; - vl_api_interface_index_t sw_if_index; + vl_api_ip4_address_t external_addr; + u16 external_port; + u8 protocol; + vl_api_nat_config_flags_t flags; + u32 affinity; + string tag[64]; + u32 local_num; + vl_api_nat44_lb_addr_port_t locals[local_num]; +}; + +/** \brief Delete NAT44 session + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param ip_address - IPv4 address + @param protocol - IP protocol + @param port - port number + @param vfr_id - VRF ID + @param flags - flag NAT_IS_INSIDE if interface is inside or + interface is outside, + flag NAT_IS_EXT_HOST_VALID if external host address and + port are valid + @param ext_host_address - external host IPv4 address + @param ext_host_port - external host port +*/ +autoreply define nat44_del_session { + u32 client_index; + u32 context; + vl_api_ip4_address_t address; + u8 protocol; + u16 port; + u32 vrf_id; vl_api_nat_config_flags_t flags; + vl_api_ip4_address_t ext_host_address; + u16 ext_host_port; }; /** \brief Dump NAT44 users @@ -1038,6 +831,8 @@ define nat44_user_details { @param vrf_id - VRF_ID */ define nat44_user_session_dump { + option deprecated; + u32 client_index; u32 context; vl_api_ip4_address_t ip_address; @@ -1066,6 +861,8 @@ define nat44_user_session_dump { twice-nat session) */ define nat44_user_session_details { + option deprecated; + u32 context; vl_api_ip4_address_t outside_ip_address; u16 outside_port; @@ -1089,7 +886,8 @@ define nat44_user_session_details { @param vrf_id - VRF_ID */ define nat44_user_session_v2_dump { - option in_progress; + option deprecated; + u32 client_index; u32 context; vl_api_ip4_address_t ip_address; @@ -1120,7 +918,8 @@ define nat44_user_session_v2_dump { is active */ define nat44_user_session_v2_details { - option in_progress; + option deprecated; + u32 context; vl_api_ip4_address_t outside_ip_address; u16 outside_port; @@ -1138,199 +937,58 @@ define nat44_user_session_v2_details { bool is_timed_out; }; -/** \brief NAT44 load-balancing address and port pair - @param addr - IPv4 address of the internal node - @param port - L4 port number of the internal node - @param probability - probability of the internal node to be randomly matched - @param vrf_id - VRF id -*/ -typedef nat44_lb_addr_port { - vl_api_ip4_address_t addr; - u16 port; - u8 probability; - u32 vrf_id; -}; - -/** \brief Add/delete NAT44 load-balancing static mapping rule - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - true if add, false if delete - @param flags - flag NAT_TWICE_NAT if NAT address range for external hosts, - flag NAT_SELF_TWICE_NAT if translate external host address - and port whenever external host address equals local - address of internal host, - flag NAT_OUT2IN_ONLY if rule match only out2in direction - @param external_addr - external IPv4 address of the service - @param external_port - external L4 port number of the service - @param protocol - IP protocol number of the service - @param affinity - if 0 disabled, otherwise client IP affinity sticky time - in seconds - @param local_num - number of local network nodes - @param locals - local network nodes - @param tag - opaque string tag -*/ -autoreply define nat44_add_del_lb_static_mapping { - u32 client_index; - u32 context; - bool is_add; - vl_api_nat_config_flags_t flags; - vl_api_ip4_address_t external_addr; - u16 external_port; - u8 protocol; - u32 affinity; - string tag[64]; - u32 local_num; - vl_api_nat44_lb_addr_port_t locals[local_num]; -}; - -/** \brief Add/delete NAT44 load-balancing static mapping rule backend - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - true if add, false if delete - @param external_addr - external IPv4 address of the service - @param external_port - external L4 port number of the service - @param protocol - IP protocol number of the service - @param local - local network node -*/ -autoreply define nat44_lb_static_mapping_add_del_local { - u32 client_index; - u32 context; - bool is_add; - vl_api_ip4_address_t external_addr; - u16 external_port; - u8 protocol; - vl_api_nat44_lb_addr_port_t local; -}; - -/** \brief Dump NAT44 load-balancing static mapping rules - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define nat44_lb_static_mapping_dump { - u32 client_index; - u32 context; -}; - -/** \brief NAT44 load-balancing static mapping rule details response - @param context - sender context, to match reply w/ request - @param external_addr - external IPv4 address of the service - @param external_port - external L4 port number of the service - @param protocol - IP protocol number of the service - @param flags - flag NAT_TWICE_NAT if NAT address range for external hosts, - flag NAT_SELF_TWICE_NAT if translate external host address - and port whenever external host address equals local - address of internal host, - flag NAT_OUT2IN_ONLY if rule match only out2in direction - @param affinity - if 0 disabled, otherwise client IP affinity sticky time - in seconds - @param local_num - number of local network nodes - @param locals - local network nodes - @param tag - opaque string tag -*/ -define nat44_lb_static_mapping_details { - u32 context; - vl_api_ip4_address_t external_addr; - u16 external_port; - u8 protocol; - vl_api_nat_config_flags_t flags; - u32 affinity; - string tag[64]; - u32 local_num; - vl_api_nat44_lb_addr_port_t locals[local_num]; -}; - -/** \brief Delete NAT44 session - @param client_index - opaque cookie to identify the sender +/** \brief NAT44 user's sessions response @param context - sender context, to match reply w/ request - @param ip_address - IPv4 address - @param protocol - IP protocol - @param port - port number - @param vfr_id - VRF ID - @param flags - flag NAT_IS_INSIDE if interface is inside or - interface is outside, - flag NAT_IS_EXT_HOST_VALID if external host address and - port are valid + @param outside_ip_address - outside IPv4 address + @param outside_port - outside port + @param inside_ip_address - inside IPv4 address + @param inside_port - inside port + @param protocol - protocol + @param flags - flag NAT_IS_STATIC if session is static, + flag NAT_IS_TWICE_NAT if session is twice-nat, + flag NAT_IS_EXT_HOST_VALID if external host address + and port are valid + @param last_heard - last heard timer since VPP start + @param time_since_last_heard - difference between current vpp time and last_heard value + @param total_bytes - count of bytes sent through session + @param total_pkts - count of pakets sent through session @param ext_host_address - external host IPv4 address @param ext_host_port - external host port + @param ext_host_nat_address - post-NAT external host IPv4 address (valid + only if twice-nat session) + @param ext_host_nat_port - post-NAT external host port (valid only if + twice-nat session) + @param is_timed_out - true, if session is timed out, and false, if session + is active */ -autoreply define nat44_del_session { - u32 client_index; +define nat44_user_session_v3_details { u32 context; - vl_api_ip4_address_t address; - u8 protocol; - u16 port; - u32 vrf_id; + vl_api_ip4_address_t outside_ip_address; + u16 outside_port; + vl_api_ip4_address_t inside_ip_address; + u16 inside_port; + u16 protocol; vl_api_nat_config_flags_t flags; + u64 last_heard; + u64 time_since_last_heard; + u64 total_bytes; + u32 total_pkts; vl_api_ip4_address_t ext_host_address; u16 ext_host_port; + vl_api_ip4_address_t ext_host_nat_address; + u16 ext_host_nat_port; + bool is_timed_out; }; -/** \brief Enable/disable forwarding for NAT44 - Forward packets which don't match existing translation - or static mapping instead of dropping them. - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param enable - true for enable, false for disable -*/ -autoreply define nat44_forwarding_enable_disable { - option deprecated; - u32 client_index; - u32 context; - bool enable; -}; - -/** \brief Check if forwarding is enabled or disabled - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define nat44_forwarding_is_enabled { - option deprecated; - u32 client_index; - u32 context; -}; - -/** \brief Response to check if forwarding is enabled or disabled - @param context - sender context, to match reply w/ request - @param enabled - true if enabled, false if disabled -*/ -define nat44_forwarding_is_enabled_reply { - option deprecated; - u32 context; - bool enabled; -}; - -/** \brief Set NAT handoff frame queue options - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param frame_queue_nelts - number of worker handoff frame queue elements -*/ -autoreply define nat44_ed_set_fq_options { - option in_progress; - u32 client_index; - u32 context; - u32 frame_queue_nelts; -}; - -/** \brief Show NAT handoff frame queue options +/** \brief NAT44 user's sessions @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request + @param ip_address - IPv4 address of the user to dump + @param vrf_id - VRF_ID */ -define nat44_ed_show_fq_options -{ - option in_progress; +define nat44_user_session_v3_dump { u32 client_index; u32 context; -}; - -/** \brief Show NAT handoff frame queue options reply - @param context - sender context, to match reply w/ request - @param retval - return code for the request - @param frame_queue_nelts - number of worker handoff frame queue elements -*/ -define nat44_ed_show_fq_options_reply -{ - option in_progress; - u32 context; - i32 retval; - u32 frame_queue_nelts; + vl_api_ip4_address_t ip_address; + u32 vrf_id; }; diff --git a/src/plugins/nat/nat44-ed/nat44_ed.c b/src/plugins/nat/nat44-ed/nat44_ed.c index f58002c156d..08e577747c3 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed.c +++ b/src/plugins/nat/nat44-ed/nat44_ed.c @@ -1,6 +1,4 @@ /* - * snat.c - simple nat plugin - * * Copyright (c) 2016 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. @@ -38,7 +36,7 @@ #include <nat/nat44-ed/nat44_ed_affinity.h> #include <nat/nat44-ed/nat44_ed_inlines.h> -#include <vpp/stats/stat_segment.h> +#include <vlib/stats/stats.h> snat_main_t snat_main; @@ -61,7 +59,7 @@ static_always_inline void nat_validate_interface_counters (snat_main_t *sm, if (PREDICT_FALSE (sm->enabled)) \ { \ nat_log_err ("plugin enabled"); \ - return 1; \ + return VNET_API_ERROR_FEATURE_ALREADY_ENABLED; \ } \ } \ while (0) @@ -73,12 +71,11 @@ static_always_inline void nat_validate_interface_counters (snat_main_t *sm, if (PREDICT_FALSE (!sm->enabled)) \ { \ nat_log_err ("plugin disabled"); \ - return 1; \ + return VNET_API_ERROR_FEATURE_ALREADY_DISABLED; \ } \ } \ while (0) -/* Hook up input features */ VNET_FEATURE_INIT (nat_pre_in2out, static) = { .arc_name = "ip4-unicast", .node_name = "nat-pre-in2out", @@ -92,6 +89,18 @@ VNET_FEATURE_INIT (nat_pre_out2in, static) = { "ip4-dhcp-client-detect", "ip4-sv-reassembly-feature"), }; +VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = { + .arc_name = "ip4-unicast", + .node_name = "nat44-ed-classify", + .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa", + "ip4-sv-reassembly-feature"), +}; +VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = { + .arc_name = "ip4-unicast", + .node_name = "nat44-handoff-classify", + .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa", + "ip4-sv-reassembly-feature"), +}; VNET_FEATURE_INIT (snat_in2out_worker_handoff, static) = { .arc_name = "ip4-unicast", .node_name = "nat44-in2out-worker-handoff", @@ -103,17 +112,6 @@ VNET_FEATURE_INIT (snat_out2in_worker_handoff, static) = { .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa", "ip4-dhcp-client-detect"), }; -VNET_FEATURE_INIT (ip4_snat_in2out, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-in2out", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"), -}; -VNET_FEATURE_INIT (ip4_snat_out2in, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-out2in", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature", - "ip4-dhcp-client-detect"), -}; VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = { .arc_name = "ip4-unicast", .node_name = "nat44-ed-in2out", @@ -125,32 +123,9 @@ VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = { .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature", "ip4-dhcp-client-detect"), }; -VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-ed-classify", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"), -}; -VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-handoff-classify", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"), -}; -VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-in2out-fast", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"), -}; -VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-out2in-fast", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature", - "ip4-dhcp-client-detect"), -}; - -/* Hook up output features */ -VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = { +VNET_FEATURE_INIT (nat_pre_in2out_output, static) = { .arc_name = "ip4-output", - .node_name = "nat44-in2out-output", + .node_name = "nat-pre-in2out-output", .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"), .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"), }; @@ -160,12 +135,6 @@ VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = { .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"), .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"), }; -VNET_FEATURE_INIT (nat_pre_in2out_output, static) = { - .arc_name = "ip4-output", - .node_name = "nat-pre-in2out-output", - .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"), - .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"), -}; VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = { .arc_name = "ip4-output", .node_name = "nat44-ed-in2out-output", @@ -178,34 +147,22 @@ VLIB_PLUGIN_REGISTER () = { .description = "Network Address Translation (NAT)", }; -static void nat44_ed_db_init (u32 translations, u32 translation_buckets); - +static void nat44_ed_db_init (); static void nat44_ed_db_free (); +static void nat44_ed_worker_db_free (snat_main_per_thread_data_t *tsm); + +static int nat44_ed_add_static_mapping_internal ( + ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, + ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags, + ip4_address_t pool_addr, u8 *tag); +static int nat44_ed_del_static_mapping_internal (ip4_address_t l_addr, + ip4_address_t e_addr, + u16 l_port, u16 e_port, + ip_protocol_t proto, + u32 vrf_id, u32 flags); u32 nat_calc_bihash_buckets (u32 n_elts); -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 *); - - u8 proto; - u16 r_port, l_port; - ip4_address_t l_addr, r_addr; - u32 fib_index; - - split_ed_kv (v, &l_addr, &r_addr, &proto, &fib_index, &l_port, &r_port); - s = format (s, - "local %U:%d remote %U:%d proto %U fib %d thread-index %u " - "session-index %u", - format_ip4_address, &l_addr, clib_net_to_host_u16 (l_port), - format_ip4_address, &r_addr, clib_net_to_host_u16 (r_port), - format_ip_protocol, proto, fib_index, - ed_value_get_thread_index (v), ed_value_get_session_index (v)); - - return s; -} - static_always_inline int nat44_ed_sm_i2o_add (snat_main_t *sm, snat_static_mapping_t *m, ip4_address_t addr, u16 port, u32 fib_index, u8 proto) @@ -283,60 +240,195 @@ nat44_ed_free_session_data (snat_main_t *sm, snat_session_t *s, } } +static ip_interface_address_t * +nat44_ed_get_ip_interface_address (u32 sw_if_index, ip4_address_t addr) +{ + snat_main_t *sm = &snat_main; + + ip_lookup_main_t *lm = &sm->ip4_main->lookup_main; + ip_interface_address_t *ia; + ip4_address_t *ip4a; + + foreach_ip_interface_address ( + lm, ia, sw_if_index, 1, ({ + ip4a = ip_interface_address_get_address (lm, ia); + nat_log_debug ("sw_if_idx: %u addr: %U ? %U", sw_if_index, + format_ip4_address, ip4a, format_ip4_address, &addr); + if (ip4a->as_u32 == addr.as_u32) + { + return ia; + } + })); + return NULL; +} + static int -is_snat_address_used_in_static_mapping (snat_main_t *sm, ip4_address_t addr) +nat44_ed_resolve_nat_addr_len (snat_address_t *ap, + snat_interface_t *interfaces) { - snat_static_mapping_t *m; - pool_foreach (m, sm->static_mappings) + ip_interface_address_t *ia; + snat_interface_t *i; + u32 fib_index; + + pool_foreach (i, interfaces) { - if (is_sm_addr_only (m->flags) || is_sm_out2in_only (m->flags) || - is_sm_identity_nat (m->flags)) + if (!nat44_ed_is_interface_outside (i)) { continue; } - if (m->external_addr.as_u32 == addr.as_u32) + + fib_index = ip4_fib_table_get_index_for_sw_if_index (i->sw_if_index); + if (fib_index != ap->fib_index) { - return 1; + continue; + } + + if ((ia = nat44_ed_get_ip_interface_address (i->sw_if_index, ap->addr))) + { + ap->addr_len = ia->address_length; + ap->sw_if_index = i->sw_if_index; + ap->net.as_u32 = ap->addr.as_u32 & ip4_main.fib_masks[ap->addr_len]; + + nat_log_debug ("pool addr %U binds to -> sw_if_idx: %u net: %U/%u", + format_ip4_address, &ap->addr, ap->sw_if_index, + format_ip4_address, &ap->net, ap->addr_len); + return 0; } } - return 0; + return 1; } static void -nat44_ed_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index, - int is_add) +nat44_ed_update_outside_if_addresses (snat_address_t *ap) +{ + snat_main_t *sm = &snat_main; + + if (!nat44_ed_resolve_nat_addr_len (ap, sm->interfaces)) + { + return; + } + + if (!nat44_ed_resolve_nat_addr_len (ap, sm->output_feature_interfaces)) + { + return; + } +} + +static void +nat44_ed_bind_if_addr_to_nat_addr (u32 sw_if_index) +{ + snat_main_t *sm = &snat_main; + ip_interface_address_t *ia; + snat_address_t *ap; + + u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); + + vec_foreach (ap, sm->addresses) + { + if (fib_index != ap->fib_index) + { + continue; + } + + if ((ia = nat44_ed_get_ip_interface_address (sw_if_index, ap->addr))) + { + ap->addr_len = ia->address_length; + ap->sw_if_index = sw_if_index; + ap->net.as_u32 = ap->addr.as_u32 & ip4_main.fib_masks[ap->addr_len]; + + nat_log_debug ("pool addr %U binds to -> sw_if_idx: %u net: %U/%u", + format_ip4_address, &ap->addr, ap->sw_if_index, + format_ip4_address, &ap->net, ap->addr_len); + return; + } + } +} + +static_always_inline snat_fib_entry_reg_t * +nat44_ed_get_fib_entry_reg (ip4_address_t addr, u32 sw_if_index, int *out_idx) +{ + snat_main_t *sm = &snat_main; + snat_fib_entry_reg_t *fe; + int i; + + for (i = 0; i < vec_len (sm->fib_entry_reg); i++) + { + fe = sm->fib_entry_reg + i; + if ((addr.as_u32 == fe->addr.as_u32) && (sw_if_index == fe->sw_if_index)) + { + if (out_idx) + { + *out_idx = i; + } + return fe; + } + } + return NULL; +} + +static void +nat44_ed_add_fib_entry_reg (ip4_address_t addr, u32 sw_if_index) { // Add the external NAT address to the FIB as receive entries. This ensures // that VPP will reply to ARP for this address and we don't need to enable // proxy ARP on the outside interface. - snat_main_t *sm = &snat_main; - fib_prefix_t prefix = { - .fp_len = p_len, - .fp_proto = FIB_PROTOCOL_IP4, - .fp_addr = { - .ip4.as_u32 = addr->as_u32, - }, - }; - u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); + snat_fib_entry_reg_t *fe; - if (is_add) + if (!(fe = nat44_ed_get_fib_entry_reg (addr, sw_if_index, 0))) { + fib_prefix_t prefix = { + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_addr = { + .ip4.as_u32 = addr.as_u32, + }, + }; + u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index); fib_table_entry_update_one_path (fib_index, &prefix, sm->fib_src_low, (FIB_ENTRY_FLAG_CONNECTED | FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_EXCLUSIVE), DPO_PROTO_IP4, NULL, sw_if_index, ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE); + + vec_add2 (sm->fib_entry_reg, fe, 1); + clib_memset (fe, 0, sizeof (*fe)); + fe->addr.as_u32 = addr.as_u32; + fe->sw_if_index = sw_if_index; } - else + fe->count++; +} + +static void +nat44_ed_del_fib_entry_reg (ip4_address_t addr, u32 sw_if_index) +{ + snat_main_t *sm = &snat_main; + snat_fib_entry_reg_t *fe; + int i; + + if ((fe = nat44_ed_get_fib_entry_reg (addr, sw_if_index, &i))) { - fib_table_entry_delete (fib_index, &prefix, sm->fib_src_low); + fe->count--; + if (0 == fe->count) + { + fib_prefix_t prefix = { + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_addr = { + .ip4.as_u32 = addr.as_u32, + }, + }; + u32 fib_index = + ip4_fib_table_get_index_for_sw_if_index (sw_if_index); + fib_table_entry_delete (fib_index, &prefix, sm->fib_src_low); + vec_del1 (sm->fib_entry_reg, i); + } } } static void -nat44_ed_add_del_addr_to_fib_foreach_out_if (ip4_address_t *addr, u8 is_add) +nat44_ed_add_del_interface_fib_reg_entries (ip4_address_t addr, u8 is_add) { snat_main_t *sm = &snat_main; snat_interface_t *i; @@ -345,42 +437,66 @@ nat44_ed_add_del_addr_to_fib_foreach_out_if (ip4_address_t *addr, u8 is_add) { if (nat44_ed_is_interface_outside (i)) { - nat44_ed_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add); + if (is_add) + { + nat44_ed_add_fib_entry_reg (addr, i->sw_if_index); + } + else + { + nat44_ed_del_fib_entry_reg (addr, i->sw_if_index); + } } } pool_foreach (i, sm->output_feature_interfaces) { if (nat44_ed_is_interface_outside (i)) { - nat44_ed_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add); + if (is_add) + { + nat44_ed_add_fib_entry_reg (addr, i->sw_if_index); + } + else + { + nat44_ed_del_fib_entry_reg (addr, i->sw_if_index); + } } } } static_always_inline void -nat44_ed_add_del_addr_to_fib_foreach_addr (u32 sw_if_index, u8 is_add) +nat44_ed_add_del_nat_addr_fib_reg_entries (u32 sw_if_index, u8 is_add) { snat_main_t *sm = &snat_main; snat_address_t *ap; vec_foreach (ap, sm->addresses) { - nat44_ed_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, is_add); + if (is_add) + { + nat44_ed_add_fib_entry_reg (ap->addr, sw_if_index); + } + else + { + nat44_ed_del_fib_entry_reg (ap->addr, sw_if_index); + } } } static_always_inline void -nat44_ed_add_del_addr_to_fib_foreach_addr_only_sm (u32 sw_if_index, u8 is_add) +nat44_ed_add_del_sm_fib_reg_entries (u32 sw_if_index, u8 is_add) { snat_main_t *sm = &snat_main; snat_static_mapping_t *m; pool_foreach (m, sm->static_mappings) { - if (is_sm_addr_only (m->flags) && !is_sm_identity_nat (m->flags)) + if (is_add) { - nat44_ed_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, - is_add); + nat44_ed_add_fib_entry_reg (m->external_addr, sw_if_index); + } + else + { + nat44_ed_del_fib_entry_reg (m->external_addr, sw_if_index); } } } @@ -417,6 +533,7 @@ nat44_ed_add_address (ip4_address_t *addr, u32 vrf_id, u8 twice_nat) vec_add2 (sm->addresses, ap, 1); } + ap->addr_len = ~0; ap->fib_index = ~0; ap->addr = *addr; @@ -426,24 +543,24 @@ nat44_ed_add_address (ip4_address_t *addr, u32 vrf_id, u8 twice_nat) FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low); } - if (!twice_nat) - { - // if we don't have enabled interface we don't add address - // to fib - nat44_ed_add_del_addr_to_fib_foreach_out_if (addr, 1); - } + if (!twice_nat) + { + // if we don't have enabled interface we don't add address + // to fib + nat44_ed_add_del_interface_fib_reg_entries (*addr, 1); + nat44_ed_update_outside_if_addresses (ap); + } return 0; } int -nat44_ed_del_address (ip4_address_t addr, u8 delete_sm, u8 twice_nat) +nat44_ed_del_address (ip4_address_t addr, u8 twice_nat) { snat_main_t *sm = &snat_main; snat_address_t *a = 0, *addresses; snat_session_t *ses; u32 *ses_to_be_removed = 0, *ses_index; snat_main_per_thread_data_t *tsm; - snat_static_mapping_t *m; int j; addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses; @@ -462,61 +579,177 @@ nat44_ed_del_address (ip4_address_t addr, u8 delete_sm, u8 twice_nat) return VNET_API_ERROR_NO_SUCH_ENTRY; } - if (delete_sm) + // delete dynamic sessions only + vec_foreach (tsm, sm->per_thread_data) { - pool_foreach (m, sm->static_mappings) + pool_foreach (ses, tsm->sessions) { - if (m->external_addr.as_u32 == addr.as_u32) + if (ses->flags & SNAT_SESSION_FLAG_STATIC_MAPPING) + { + continue; + } + if (ses->out2in.addr.as_u32 == addr.as_u32) { - nat44_ed_del_static_mapping (m->local_addr, m->external_addr, - m->local_port, m->external_port, - ip_proto_to_nat_proto (m->proto), - m->vrf_id, ~0, m->flags); + nat44_ed_free_session_data (sm, ses, tsm - sm->per_thread_data, + 0); + vec_add1 (ses_to_be_removed, ses - tsm->sessions); } } + vec_foreach (ses_index, ses_to_be_removed) + { + ses = pool_elt_at_index (tsm->sessions, ses_index[0]); + nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1); + } + vec_free (ses_to_be_removed); + } + + if (!twice_nat) + { + nat44_ed_add_del_interface_fib_reg_entries (addr, 0); + } + + if (a->fib_index != ~0) + { + fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + } + + if (!twice_nat) + { + vec_del1 (sm->addresses, j); } else { - // TODO: why ? - // check if address is used in some static mapping - if (is_snat_address_used_in_static_mapping (sm, addr)) + vec_del1 (sm->twice_nat_addresses, j); + } + + return 0; +} + +vrf_table_t * +nat44_ed_get_vrf_table (u32 table_vrf_id) +{ + snat_main_t *sm = &snat_main; + vrf_table_t *t; + + pool_foreach (t, sm->vrf_tables) + { + if (table_vrf_id == t->table_vrf_id) { - nat_log_err ("address used in static mapping"); - return VNET_API_ERROR_UNSPECIFIED; + return t; } } + return NULL; +} - if (a->fib_index != ~0) +vrf_route_t * +nat44_ed_get_vrf_route (vrf_table_t *t, u32 vrf_id) +{ + vrf_route_t *r; + + pool_foreach (r, t->routes) { - fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + if (vrf_id == r->vrf_id) + { + return r; + } } + return NULL; +} - // delete sessions using address - vec_foreach (tsm, sm->per_thread_data) +int +nat44_ed_add_del_vrf_table (u32 table_vrf_id, bool is_add) +{ + snat_main_t *sm = &snat_main; + vrf_table_t *t; + vrf_route_t *r; + + t = nat44_ed_get_vrf_table (table_vrf_id); + if (t) { - pool_foreach (ses, tsm->sessions) + if (is_add) { - if (ses->out2in.addr.as_u32 == addr.as_u32) - { - nat44_ed_free_session_data (sm, ses, tsm - sm->per_thread_data, - 0); - vec_add1 (ses_to_be_removed, ses - tsm->sessions); - } + return VNET_API_ERROR_VALUE_EXIST; } - vec_foreach (ses_index, ses_to_be_removed) + pool_foreach (r, t->routes) { - ses = pool_elt_at_index (tsm->sessions, ses_index[0]); - nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1); + fib_table_unlock (r->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); } - vec_free (ses_to_be_removed); + fib_table_unlock (t->table_fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + + pool_free (t->routes); + pool_put (sm->vrf_tables, t); + } + else + { + if (!is_add) + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + pool_get (sm->vrf_tables, t); + clib_memset (t, 0, sizeof (*t)); + t->table_vrf_id = table_vrf_id; + t->table_fib_index = fib_table_find_or_create_and_lock ( + FIB_PROTOCOL_IP4, table_vrf_id, sm->fib_src_low); + } + + return 0; +} + +void +nat44_ed_del_vrf_tables () +{ + snat_main_t *sm = &snat_main; + vrf_table_t *t; + vrf_route_t *r; + + pool_foreach (t, sm->vrf_tables) + { + pool_foreach (r, t->routes) + { + fib_table_unlock (r->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + } + fib_table_unlock (t->table_fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + pool_free (t->routes); + } + pool_free (sm->vrf_tables); +} + +int +nat44_ed_add_del_vrf_route (u32 table_vrf_id, u32 vrf_id, bool is_add) +{ + snat_main_t *sm = &snat_main; + vrf_table_t *t; + vrf_route_t *r; + + t = nat44_ed_get_vrf_table (table_vrf_id); + if (!t) + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + + r = nat44_ed_get_vrf_route (t, vrf_id); + if (r) + { + if (is_add) + { + return VNET_API_ERROR_VALUE_EXIST; + } + fib_table_unlock (r->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); + pool_put (t->routes, r); + } + else + { + if (!is_add) + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + pool_get (t->routes, r); + clib_memset (r, 0, sizeof (*r)); + r->vrf_id = vrf_id; + r->fib_index = fib_table_find_or_create_and_lock ( + FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low); } - if (!twice_nat) - { - vec_del1 (sm->addresses, j); - nat44_ed_add_del_addr_to_fib_foreach_out_if (&addr, 0); - } - else { vec_del1 (sm->twice_nat_addresses, j); } return 0; } @@ -527,9 +760,9 @@ get_thread_idx_by_port (u16 e_port) u32 thread_idx = sm->num_workers; if (sm->num_workers > 1) { - thread_idx = - sm->first_worker_index + - sm->workers[(e_port - 1024) / sm->port_per_thread]; + thread_idx = sm->first_worker_index + + sm->workers[(e_port - ED_USER_PORT_OFFSET) / + sm->port_per_thread % _vec_len (sm->workers)]; } return thread_idx; } @@ -609,38 +842,18 @@ nat44_ed_sm_i2o_lookup (snat_main_t *sm, ip4_address_t addr, u16 port, return nat44_ed_sm_lookup (sm, &kv); } -void -nat44_ed_add_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, - ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, - u32 flags, ip4_address_t pool_addr, u8 *tag) -{ - snat_static_map_resolve_t *rp; - snat_main_t *sm = &snat_main; - - vec_add2 (sm->to_resolve, rp, 1); - rp->l_addr.as_u32 = l_addr.as_u32; - rp->l_port = l_port; - rp->e_port = e_port; - rp->sw_if_index = sw_if_index; - rp->vrf_id = vrf_id; - rp->proto = proto; - rp->flags = flags; - rp->pool_addr = pool_addr; - rp->tag = vec_dup (tag); -} - -int +static snat_static_mapping_resolve_t * nat44_ed_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, - u32 flags, int *out) + u32 flags, int *out_idx) { - snat_static_map_resolve_t *rp; + snat_static_mapping_resolve_t *rp; snat_main_t *sm = &snat_main; int i; - for (i = 0; i < vec_len (sm->to_resolve); i++) + for (i = 0; i < vec_len (sm->sm_to_resolve); i++) { - rp = sm->to_resolve + i; + rp = sm->sm_to_resolve + i; if (rp->sw_if_index == sw_if_index && rp->vrf_id == vrf_id) { @@ -669,27 +882,27 @@ nat44_ed_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, { continue; } - if (out) + if (out_idx) { - *out = i; + *out_idx = i; } - return 0; + return rp; } } - return 1; + return NULL; } -int +static int nat44_ed_del_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port, ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags) { snat_main_t *sm = &snat_main; int i; - if (!nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, - sw_if_index, flags, &i)) + if (nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags, &i)) { - vec_del1 (sm->to_resolve, i); + vec_del1 (sm->sm_to_resolve, i); return 0; } return 1; @@ -714,27 +927,14 @@ nat44_ed_validate_sm_input (u32 flags) return 0; } -snat_address_t * -nat44_ed_addr_lookup (snat_main_t *sm, u32 addr) -{ - for (int i = 0; i < vec_len (sm->addresses); ++i) - { - if (sm->addresses[i].addr.as_u32 == addr) - return &sm->addresses[i]; - } - return NULL; -} - int nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags, ip4_address_t pool_addr, u8 *tag) { + snat_static_mapping_resolve_t *rp; snat_main_t *sm = &snat_main; - nat44_lb_addr_port_t *local; - snat_static_mapping_t *m; - u32 fib_index = ~0; int rv; if (!sm->enabled) @@ -748,27 +948,79 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, return rv; } - if (is_sm_addr_only (flags)) + // interface bound mapping + if (is_sm_switch_address (flags)) { - e_port = l_port = proto = 0; + if (nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags, 0)) + { + return VNET_API_ERROR_VALUE_EXIST; + } + + vec_add2 (sm->sm_to_resolve, rp, 1); + rp->l_addr.as_u32 = l_addr.as_u32; + rp->l_port = l_port; + rp->e_port = e_port; + rp->sw_if_index = sw_if_index; + rp->vrf_id = vrf_id; + rp->proto = proto; + rp->flags = flags; + rp->pool_addr = pool_addr; + rp->tag = vec_dup (tag); + rp->is_resolved = 0; + + ip4_address_t *first_int_addr = + ip4_interface_first_address (sm->ip4_main, sw_if_index, 0); + if (!first_int_addr) + { + return 0; + } + + e_addr.as_u32 = first_int_addr->as_u32; + rp->is_resolved = 1; } - if (is_sm_switch_address (flags)) + rv = nat44_ed_add_static_mapping_internal (l_addr, e_addr, l_port, e_port, + proto, vrf_id, sw_if_index, flags, + pool_addr, tag); + if ((0 != rv) && is_sm_switch_address (flags)) + { + nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags); + } + + return rv; +} + +int +nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, + u16 l_port, u16 e_port, ip_protocol_t proto, + u32 vrf_id, u32 sw_if_index, u32 flags) +{ + snat_main_t *sm = &snat_main; + int rv; + + if (!sm->enabled) { - // this mapping is interface bound - ip4_address_t *first_int_addr; + return VNET_API_ERROR_UNSUPPORTED; + } - // check if this record isn't registered for resolve - if (!nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, - sw_if_index, flags, 0)) + rv = nat44_ed_validate_sm_input (flags); + if (rv != 0) + { + return rv; + } + + // interface bound mapping + if (is_sm_switch_address (flags)) + { + if (nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags)) { - return VNET_API_ERROR_VALUE_EXIST; + return VNET_API_ERROR_NO_SUCH_ENTRY; } - // register record for resolve - nat44_ed_add_resolve_record (l_addr, l_port, e_port, proto, vrf_id, - sw_if_index, flags, pool_addr, tag); - first_int_addr = + ip4_address_t *first_int_addr = ip4_interface_first_address (sm->ip4_main, sw_if_index, 0); if (!first_int_addr) { @@ -779,6 +1031,27 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, e_addr.as_u32 = first_int_addr->as_u32; } + return nat44_ed_del_static_mapping_internal (l_addr, e_addr, l_port, e_port, + proto, vrf_id, flags); +} + +static int +nat44_ed_add_static_mapping_internal (ip4_address_t l_addr, + ip4_address_t e_addr, u16 l_port, + u16 e_port, ip_protocol_t proto, + u32 vrf_id, u32 sw_if_index, u32 flags, + ip4_address_t pool_addr, u8 *tag) +{ + snat_main_t *sm = &snat_main; + nat44_lb_addr_port_t *local; + snat_static_mapping_t *m; + u32 fib_index = ~0; + + if (is_sm_addr_only (flags)) + { + e_port = l_port = proto = 0; + } + if (is_sm_identity_nat (flags)) { l_port = e_port; @@ -788,13 +1061,14 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, m = nat44_ed_sm_o2i_lookup (sm, e_addr, e_port, 0, proto); if (m) { + // case: + // adding local identity nat record for different vrf table + if (!is_sm_identity_nat (m->flags)) { return VNET_API_ERROR_VALUE_EXIST; } - // case: - // adding local identity nat record for different vrf table pool_foreach (local, m->locals) { if (local->vrf_id == vrf_id) @@ -838,21 +1112,6 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, } } - if (!(is_sm_out2in_only (flags) || is_sm_addr_only (flags) || - sm->static_mapping_only)) - { - if (!nat44_ed_addr_lookup (sm, e_addr.as_u32)) - { - // remove resolve record - if (is_sm_switch_address (flags) && !is_sm_identity_nat (flags)) - { - nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto, - vrf_id, sw_if_index, flags); - } - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - } - pool_get (sm->static_mappings, m); clib_memset (m, 0, sizeof (*m)); @@ -860,13 +1119,9 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, m->local_addr = l_addr; m->external_addr = e_addr; + m->pool_addr = pool_addr; m->tag = vec_dup (tag); - if (is_sm_exact_address (flags) && is_sm_twice_nat (flags)) - { - m->pool_addr = pool_addr; - } - if (!is_sm_addr_only (flags)) { m->local_port = l_port; @@ -885,12 +1140,6 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, { m->vrf_id = vrf_id; m->fib_index = fib_index; - - // not identity && addr only - if (is_sm_addr_only (flags)) - { - nat44_ed_add_del_addr_to_fib_foreach_out_if (&e_addr, 1); - } } if (!is_sm_out2in_only (flags)) @@ -913,13 +1162,16 @@ nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, vec_add1 (m->workers, worker_index); } + nat44_ed_add_del_interface_fib_reg_entries (e_addr, 1); + return 0; } -int -nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, ip_protocol_t proto, - u32 vrf_id, u32 sw_if_index, u32 flags) +static int +nat44_ed_del_static_mapping_internal (ip4_address_t l_addr, + ip4_address_t e_addr, u16 l_port, + u16 e_port, ip_protocol_t proto, + u32 vrf_id, u32 flags) { snat_main_per_thread_data_t *tsm; snat_main_t *sm = &snat_main; @@ -927,47 +1179,12 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, nat44_lb_addr_port_t *local; snat_static_mapping_t *m; u32 fib_index = ~0; - int rv; - - if (!sm->enabled) - { - return VNET_API_ERROR_UNSUPPORTED; - } - - rv = nat44_ed_validate_sm_input (flags); - if (rv != 0) - { - return rv; - } if (is_sm_addr_only (flags)) { e_port = l_port = proto = 0; } - if (is_sm_switch_address (flags)) - { - // this mapping is interface bound - ip4_address_t *first_int_addr; - - // delete record registered for resolve - if (nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id, - sw_if_index, flags)) - { - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - first_int_addr = - ip4_interface_first_address (sm->ip4_main, sw_if_index, 0); - if (!first_int_addr) - { - // dhcp resolution required - return 0; - } - - e_addr.as_u32 = first_int_addr->as_u32; - } - if (is_sm_identity_nat (flags)) { l_port = e_port; @@ -976,21 +1193,16 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, // fib index 0 m = nat44_ed_sm_o2i_lookup (sm, e_addr, e_port, 0, proto); - if (!m) { - if (is_sm_switch_address (flags)) - { - return 0; - } return VNET_API_ERROR_NO_SUCH_ENTRY; } if (is_sm_identity_nat (flags)) { - u8 failure = 1; + u8 found = 0; - if (!is_sm_switch_address (flags)) + if (vrf_id == ~0) { vrf_id = sm->inside_vrf_id; } @@ -1002,11 +1214,11 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, local = pool_elt_at_index (m->locals, local - m->locals); fib_index = local->fib_index; pool_put (m->locals, local); - failure = 0; + found = 1; } } - if (failure) + if (!found) { return VNET_API_ERROR_NO_SUCH_ENTRY; } @@ -1016,33 +1228,25 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, fib_index = m->fib_index; } - if (!(is_sm_out2in_only (flags) || is_sm_addr_only (flags) || - sm->static_mapping_only)) - { - if (!nat44_ed_addr_lookup (sm, e_addr.as_u32)) - { - return VNET_API_ERROR_INVALID_VALUE; - } - } - if (!is_sm_out2in_only (flags)) { nat44_ed_sm_i2o_del (sm, l_addr, l_port, fib_index, proto); } - if (!sm->static_mapping_only || sm->static_mapping_connection_tracking) + // delete sessions for static mapping + if (sm->num_workers > 1) { - // delete sessions for static mapping - if (sm->num_workers > 1) - tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]); - else - tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); - - nat_ed_static_mapping_del_sessions ( - sm, tsm, m->local_addr, m->local_port, m->proto, fib_index, - is_sm_addr_only (flags), e_addr, e_port); + tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]); + } + else + { + tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); } + nat_ed_static_mapping_del_sessions (sm, tsm, m->local_addr, m->local_port, + m->proto, fib_index, + is_sm_addr_only (flags), e_addr, e_port); + fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low); if (!pool_elts (m->locals)) @@ -1055,10 +1259,7 @@ nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, vec_free (m->workers); pool_put (sm->static_mappings, m); - if (is_sm_addr_only (flags) && !is_sm_identity_nat (flags)) - { - nat44_ed_add_del_addr_to_fib_foreach_out_if (&e_addr, 0); - } + nat44_ed_add_del_interface_fib_reg_entries (e_addr, 0); } return 0; @@ -1097,7 +1298,7 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, return VNET_API_ERROR_INVALID_VALUE; } - if (!(sm->static_mapping_only || is_sm_out2in_only (flags))) + if (!is_sm_out2in_only (flags)) { /* Find external address in allocated addresses and reserve port for address and port pair mapping when dynamic translations enabled */ @@ -1141,7 +1342,7 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, if (nat44_ed_sm_o2i_add (sm, m, m->external_addr, m->external_port, 0, m->proto)) { - nat_elog_err (sm, "sm o2i key add failed"); + nat_log_err ("sm o2i key add failed"); return VNET_API_ERROR_UNSPECIFIED; } @@ -1151,9 +1352,10 @@ nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port, FIB_PROTOCOL_IP4, locals[i].vrf_id, sm->fib_src_low); if (!is_sm_out2in_only (flags)) { - if (nat44_ed_sm_o2i_add (sm, m, e_addr, e_port, 0, proto)) + if (nat44_ed_sm_i2o_add (sm, m, locals[i].addr, locals[i].port, 0, + proto)) { - nat_elog_err (sm, "sm o2i key add failed"); + nat_log_err ("sm i2o key add failed"); rc = VNET_API_ERROR_UNSPECIFIED; // here we continue with add operation so that it can be safely // reversed in delete path - otherwise we'd have to track what @@ -1216,7 +1418,7 @@ nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, if (nat44_ed_sm_o2i_del (sm, m->external_addr, m->external_port, 0, m->proto)) { - nat_elog_err (sm, "sm o2i key del failed"); + nat_log_err ("sm o2i key del failed"); return VNET_API_ERROR_UNSPECIFIED; } @@ -1228,8 +1430,8 @@ nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, if (nat44_ed_sm_i2o_del (sm, local->addr, local->port, local->fib_index, m->proto)) { - nat_elog_err (sm, "sm i2o key del failed"); - return VNET_API_ERROR_UNSPECIFIED; + nat_log_err ("sm i2o key del failed"); + // For the same reasons as above } } @@ -1337,7 +1539,7 @@ nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port, if (nat44_ed_sm_i2o_add (sm, m, l_addr, l_port, local->fib_index, proto)) { - nat_elog_err (sm, "sm i2o key add failed"); + nat_log_err ("sm i2o key add failed"); pool_put (m->locals, local); return VNET_API_ERROR_UNSPECIFIED; } @@ -1358,7 +1560,7 @@ nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port, { if (nat44_ed_sm_i2o_del (sm, l_addr, l_port, match_local->fib_index, proto)) - nat_elog_err (sm, "sm i2o key del failed"); + nat_log_err ("sm i2o key del failed"); } if (sm->num_workers > 1) @@ -1433,19 +1635,19 @@ expire_per_vrf_sessions (u32 fib_index) vec_foreach (tsm, sm->per_thread_data) { - vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec) - { - if ((per_vrf_sessions->rx_fib_index == fib_index) || - (per_vrf_sessions->tx_fib_index == fib_index)) - { - per_vrf_sessions->expired = 1; - } - } + pool_foreach (per_vrf_sessions, tsm->per_vrf_sessions_pool) + { + if ((per_vrf_sessions->rx_fib_index == fib_index) || + (per_vrf_sessions->tx_fib_index == fib_index)) + { + per_vrf_sessions->expired = 1; + } + } } } void -update_per_vrf_sessions_vec (u32 fib_index, int is_del) +update_per_vrf_sessions_pool (u32 fib_index, int is_del) { snat_main_t *sm = &snat_main; nat_fib_t *fib; @@ -1481,10 +1683,10 @@ update_per_vrf_sessions_vec (u32 fib_index, int is_del) } } -static_always_inline nat_outside_fib_t * -nat44_ed_get_outside_fib (nat_outside_fib_t *outside_fibs, u32 fib_index) +static_always_inline nat_fib_t * +nat44_ed_get_outside_fib (nat_fib_t *outside_fibs, u32 fib_index) { - nat_outside_fib_t *f; + nat_fib_t *f; vec_foreach (f, outside_fibs) { if (f->fib_index == fib_index) @@ -1515,7 +1717,7 @@ nat44_ed_add_interface (u32 sw_if_index, u8 is_inside) const char *del_feature_name, *feature_name; snat_main_t *sm = &snat_main; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; snat_interface_t *i; u32 fib_index; int rv; @@ -1588,7 +1790,7 @@ nat44_ed_add_interface (u32 sw_if_index, u8 is_inside) fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); - update_per_vrf_sessions_vec (fib_index, 0 /*is_del*/); + update_per_vrf_sessions_pool (fib_index, 0 /*is_del*/); if (!is_inside) { @@ -1597,17 +1799,19 @@ nat44_ed_add_interface (u32 sw_if_index, u8 is_inside) outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index); if (outside_fib) { - outside_fib->refcount++; + outside_fib->ref_count++; } else { vec_add2 (sm->outside_fibs, outside_fib, 1); outside_fib->fib_index = fib_index; - outside_fib->refcount = 1; + outside_fib->ref_count = 1; } - nat44_ed_add_del_addr_to_fib_foreach_addr (sw_if_index, 1); - nat44_ed_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1); + nat44_ed_add_del_nat_addr_fib_reg_entries (sw_if_index, 1); + nat44_ed_add_del_sm_fib_reg_entries (sw_if_index, 1); + + nat44_ed_bind_if_addr_to_nat_addr (sw_if_index); } else { @@ -1623,7 +1827,7 @@ nat44_ed_del_interface (u32 sw_if_index, u8 is_inside) const char *del_feature_name, *feature_name; snat_main_t *sm = &snat_main; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; snat_interface_t *i; u32 fib_index; int rv; @@ -1701,22 +1905,22 @@ nat44_ed_del_interface (u32 sw_if_index, u8 is_inside) fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); - update_per_vrf_sessions_vec (fib_index, 1 /*is_del*/); + update_per_vrf_sessions_pool (fib_index, 1 /*is_del*/); if (!is_inside) { outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index); if (outside_fib) { - outside_fib->refcount--; - if (!outside_fib->refcount) + outside_fib->ref_count--; + if (!outside_fib->ref_count) { vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); } } - nat44_ed_add_del_addr_to_fib_foreach_addr (sw_if_index, 0); - nat44_ed_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 0); + nat44_ed_add_del_nat_addr_fib_reg_entries (sw_if_index, 0); + nat44_ed_add_del_sm_fib_reg_entries (sw_if_index, 0); } return 0; @@ -1727,7 +1931,7 @@ nat44_ed_add_output_interface (u32 sw_if_index) { snat_main_t *sm = &snat_main; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; snat_interface_t *i; u32 fib_index; int rv; @@ -1800,22 +2004,24 @@ nat44_ed_add_output_interface (u32 sw_if_index) fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); - update_per_vrf_sessions_vec (fib_index, 0 /*is_del*/); + update_per_vrf_sessions_pool (fib_index, 0 /*is_del*/); outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index); if (outside_fib) { - outside_fib->refcount++; + outside_fib->ref_count++; } else { vec_add2 (sm->outside_fibs, outside_fib, 1); outside_fib->fib_index = fib_index; - outside_fib->refcount = 1; + outside_fib->ref_count = 1; } - nat44_ed_add_del_addr_to_fib_foreach_addr (sw_if_index, 1); - nat44_ed_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1); + nat44_ed_add_del_nat_addr_fib_reg_entries (sw_if_index, 1); + nat44_ed_add_del_sm_fib_reg_entries (sw_if_index, 1); + + nat44_ed_bind_if_addr_to_nat_addr (sw_if_index); return 0; } @@ -1825,7 +2031,7 @@ nat44_ed_del_output_interface (u32 sw_if_index) { snat_main_t *sm = &snat_main; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; snat_interface_t *i; u32 fib_index; int rv; @@ -1888,20 +2094,20 @@ nat44_ed_del_output_interface (u32 sw_if_index) fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index); - update_per_vrf_sessions_vec (fib_index, 1 /*is_del*/); + update_per_vrf_sessions_pool (fib_index, 1 /*is_del*/); outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index); if (outside_fib) { - outside_fib->refcount--; - if (!outside_fib->refcount) + outside_fib->ref_count--; + if (!outside_fib->ref_count) { vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); } } - nat44_ed_add_del_addr_to_fib_foreach_addr (sw_if_index, 0); - nat44_ed_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 0); + nat44_ed_add_del_nat_addr_fib_reg_entries (sw_if_index, 0); + nat44_ed_add_del_sm_fib_reg_entries (sw_if_index, 0); return 0; } @@ -1927,7 +2133,7 @@ snat_set_workers (uword * bitmap) j++; } - sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers); + sm->port_per_thread = (65536 - ED_USER_PORT_OFFSET) / _vec_len (sm->workers); return 0; } @@ -1937,6 +2143,18 @@ nat44_ed_set_frame_queue_nelts (u32 frame_queue_nelts) { fail_if_enabled (); snat_main_t *sm = &snat_main; + + if ((sm->fq_in2out_index != ~0) || (sm->fq_out2in_index != ~0) || + (sm->fq_in2out_output_index != ~0)) + { + // frame queu nelts can be set only before first + // call to nat44_plugin_enable after that it + // doesn't make sense + nat_log_err ("Frame queue was already initialized. " + "Change is not possible"); + return 1; + } + sm->frame_queue_nelts = frame_queue_nelts; return 0; } @@ -1946,7 +2164,7 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index, u32 new_fib_index, u32 old_fib_index) { snat_main_t *sm = &snat_main; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; snat_interface_t *i; u8 is_add = 1; u8 match = 0; @@ -1958,7 +2176,7 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index, } pool_foreach (i, sm->interfaces) - { + { if (i->sw_if_index == sw_if_index) { if (!(nat44_ed_is_interface_outside (i))) @@ -1968,7 +2186,7 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index, } pool_foreach (i, sm->output_feature_interfaces) - { + { if (i->sw_if_index == sw_if_index) { if (!(nat44_ed_is_interface_outside (i))) @@ -1981,30 +2199,30 @@ nat44_ed_update_outside_fib_cb (ip4_main_t *im, uword opaque, u32 sw_if_index, return; vec_foreach (outside_fib, sm->outside_fibs) - { - if (outside_fib->fib_index == old_fib_index) - { - outside_fib->refcount--; - if (!outside_fib->refcount) - vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); - break; - } - } + { + if (outside_fib->fib_index == old_fib_index) + { + outside_fib->ref_count--; + if (!outside_fib->ref_count) + vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs); + break; + } + } vec_foreach (outside_fib, sm->outside_fibs) - { - if (outside_fib->fib_index == new_fib_index) - { - outside_fib->refcount++; - is_add = 0; - break; - } - } + { + if (outside_fib->fib_index == new_fib_index) + { + outside_fib->ref_count++; + is_add = 0; + break; + } + } if (is_add) { vec_add2 (sm->outside_fibs, outside_fib, 1); - outside_fib->refcount = 1; + outside_fib->ref_count = 1; outside_fib->fib_index = new_fib_index; } } @@ -2017,7 +2235,7 @@ static void nat44_ed_add_del_interface_address_cb ( ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete); -static void nat44_ed_add_del_static_mapping_addr_only_cb ( +static void nat44_ed_add_del_static_mapping_cb ( ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete); @@ -2080,21 +2298,6 @@ nat_ip_table_add_del (vnet_main_t * vnm, u32 table_id, u32 is_add) VNET_IP_TABLE_ADD_DEL_FUNCTION (nat_ip_table_add_del); -void -nat44_set_node_indexes (snat_main_t * sm, vlib_main_t * vm) -{ - vlib_node_t *node; - - node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in"); - sm->out2in_node_index = node->index; - - node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out"); - sm->in2out_node_index = node->index; - - node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-output"); - sm->in2out_output_node_index = node->index; -} - #define nat_validate_simple_counter(c, i) \ do \ { \ @@ -2138,12 +2341,8 @@ nat_init (vlib_main_t * vm) clib_memset (sm, 0, sizeof (*sm)); - // required - sm->vnet_main = vnet_get_main (); // convenience sm->ip4_main = &ip4_main; - sm->api_main = vlibapi_get_main (); - sm->ip4_lookup_main = &ip4_main.lookup_main; // frame queue indices used for handoff sm->fq_out2in_index = ~0; @@ -2152,15 +2351,13 @@ nat_init (vlib_main_t * vm) sm->log_level = NAT_LOG_ERROR; - nat44_set_node_indexes (sm, vm); - sm->log_class = vlib_log_register_class ("nat", 0); nat_ipfix_logging_init (vm); nat_init_simple_counter (sm->total_sessions, "total-sessions", "/nat44-ed/total-sessions"); - sm->max_cfg_sessions_gauge = stat_segment_new_entry ( - (u8 *) "/nat44-ed/max-cfg-sessions", STAT_DIR_TYPE_SCALAR_INDEX); + sm->max_cfg_sessions_gauge = + vlib_stats_add_gauge ("/nat44-ed/max-cfg-sessions"); #define _(x) \ nat_init_simple_counter (sm->counters.fastpath.in2out.x, #x, \ @@ -2187,7 +2384,7 @@ nat_init (vlib_main_t * vm) } } num_threads = tm->n_vlib_mains - 1; - sm->port_per_thread = 0xffff - 1024; + sm->port_per_thread = 65536 - ED_USER_PORT_OFFSET; vec_validate (sm->per_thread_data, num_threads); /* Use all available workers by default */ @@ -2206,7 +2403,7 @@ nat_init (vlib_main_t * vm) /* callbacks to call when interface address changes. */ cbi.function = nat44_ed_add_del_interface_address_cb; vec_add1 (sm->ip4_main->add_del_interface_address_callbacks, cbi); - cbi.function = nat44_ed_add_del_static_mapping_addr_only_cb; + cbi.function = nat44_ed_add_del_static_mapping_cb; vec_add1 (sm->ip4_main->add_del_interface_address_callbacks, cbi); /* callbacks to call when interface to table biding changes */ @@ -2235,26 +2432,15 @@ nat44_plugin_enable (nat44_config_t c) fail_if_enabled (); - if (c.static_mapping_only && !c.connection_tracking) - { - nat_log_err ("unsupported combination of configuration"); - return 1; - } - - sm->static_mapping_only = c.static_mapping_only; - sm->static_mapping_connection_tracking = c.connection_tracking; - sm->forwarding_enabled = 0; sm->mss_clamping = 0; - sm->pat = (!c.static_mapping_only || - (c.static_mapping_only && c.connection_tracking)); if (!c.sessions) c.sessions = 63 * 1024; sm->max_translations_per_thread = c.sessions; - stat_segment_set_state_counter (sm->max_cfg_sessions_gauge, - sm->max_translations_per_thread); + vlib_stats_set_gauge (sm->max_cfg_sessions_gauge, + sm->max_translations_per_thread); sm->translation_buckets = nat_calc_bihash_buckets (c.sessions); vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread); @@ -2268,7 +2454,7 @@ nat44_plugin_enable (nat44_config_t c) sm->outside_fib_index = fib_table_find_or_create_and_lock ( FIB_PROTOCOL_IP4, c.outside_vrf, sm->fib_src_hi); - nat44_ed_db_init (sm->max_translations_per_thread, sm->translation_buckets); + nat44_ed_db_init (); nat_affinity_enable (); @@ -2283,20 +2469,26 @@ nat44_plugin_enable (nat44_config_t c) if (sm->num_workers > 1) { + vlib_main_t *vm = vlib_get_main (); + vlib_node_t *node; + if (sm->fq_in2out_index == ~0) { - sm->fq_in2out_index = vlib_frame_queue_main_init ( - sm->in2out_node_index, sm->frame_queue_nelts); + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out"); + sm->fq_in2out_index = + vlib_frame_queue_main_init (node->index, sm->frame_queue_nelts); } if (sm->fq_out2in_index == ~0) { - sm->fq_out2in_index = vlib_frame_queue_main_init ( - sm->out2in_node_index, sm->frame_queue_nelts); + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in"); + sm->fq_out2in_index = + vlib_frame_queue_main_init (node->index, sm->frame_queue_nelts); } if (sm->fq_in2out_output_index == ~0) { - sm->fq_in2out_output_index = vlib_frame_queue_main_init ( - sm->in2out_output_node_index, sm->frame_queue_nelts); + node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-output"); + sm->fq_in2out_output_index = + vlib_frame_queue_main_init (node->index, sm->frame_queue_nelts); } } @@ -2306,22 +2498,52 @@ nat44_plugin_enable (nat44_config_t c) return 0; } -void -nat44_addresses_free (snat_address_t ** addresses) +int +nat44_ed_del_addresses () { - vec_free (*addresses); - *addresses = 0; + snat_main_t *sm = &snat_main; + snat_address_t *a, *vec; + int error = 0; + + vec = vec_dup (sm->addresses); + vec_foreach (a, vec) + { + error = nat44_ed_del_address (a->addr, 0); + if (error) + { + nat_log_err ("error occurred while removing adderess"); + } + } + vec_free (vec); + vec_free (sm->addresses); + sm->addresses = 0; + + vec = vec_dup (sm->twice_nat_addresses); + vec_foreach (a, vec) + { + error = nat44_ed_del_address (a->addr, 1); + if (error) + { + nat_log_err ("error occurred while removing adderess"); + } + } + vec_free (vec); + vec_free (sm->twice_nat_addresses); + sm->twice_nat_addresses = 0; + + vec_free (sm->addr_to_resolve); + sm->addr_to_resolve = 0; + + return error; } int -nat44_plugin_disable () +nat44_ed_del_interfaces () { snat_main_t *sm = &snat_main; snat_interface_t *i, *pool; int error = 0; - fail_if_disabled (); - pool = pool_dup (sm->interfaces); pool_foreach (i, pool) { @@ -2333,51 +2555,156 @@ nat44_plugin_disable () { error = nat44_ed_del_interface (i->sw_if_index, 0); } + if (error) - { - nat_log_err ("error occurred while removing interface %u", - i->sw_if_index); - } + { + nat_log_err ("error occurred while removing interface"); + } } - pool_free (sm->interfaces); pool_free (pool); + pool_free (sm->interfaces); sm->interfaces = 0; + return error; +} + +int +nat44_ed_del_output_interfaces () +{ + snat_main_t *sm = &snat_main; + snat_interface_t *i, *pool; + int error = 0; pool = pool_dup (sm->output_feature_interfaces); pool_foreach (i, pool) { error = nat44_ed_del_output_interface (i->sw_if_index); if (error) - { - nat_log_err ("error occurred while removing interface %u", - i->sw_if_index); - } + { + nat_log_err ("error occurred while removing output interface"); + } } - pool_free (sm->output_feature_interfaces); pool_free (pool); + pool_free (sm->output_feature_interfaces); sm->output_feature_interfaces = 0; + return error; +} + +static clib_error_t * +nat44_ed_sw_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add) +{ + snat_main_t *sm = &snat_main; + snat_interface_t *i; + int error = 0; + + if (is_add) + return 0; + + if (!sm->enabled) + return 0; + + i = nat44_ed_get_interface (sm->interfaces, sw_if_index); + if (i) + { + bool is_inside = nat44_ed_is_interface_inside (i); + bool is_outside = nat44_ed_is_interface_outside (i); + + if (is_inside) + { + error |= nat44_ed_del_interface (sw_if_index, 1); + } + if (is_outside) + { + error |= nat44_ed_del_interface (sw_if_index, 0); + } + + if (error) + { + nat_log_err ("error occurred while removing interface"); + } + } + + i = nat44_ed_get_interface (sm->output_feature_interfaces, sw_if_index); + if (i) + { + error = nat44_ed_del_output_interface (sw_if_index); + if (error) + { + nat_log_err ("error occurred while removing output interface"); + } + } + + return 0; +} + +VNET_SW_INTERFACE_ADD_DEL_FUNCTION (nat44_ed_sw_interface_add_del); + +int +nat44_ed_del_static_mappings () +{ + snat_main_t *sm = &snat_main; + snat_static_mapping_t *m, *pool; + int error = 0; + + pool = pool_dup (sm->static_mappings); + pool_foreach (m, pool) + { + error = nat44_ed_del_static_mapping_internal ( + m->local_addr, m->external_addr, m->local_port, m->external_port, + m->proto, m->vrf_id, m->flags); + if (error) + { + nat_log_err ("error occurred while removing mapping"); + } + } + pool_free (pool); + pool_free (sm->static_mappings); + sm->static_mappings = 0; + + vec_free (sm->sm_to_resolve); + sm->sm_to_resolve = 0; + + return error; +} + +int +nat44_plugin_disable () +{ + snat_main_t *sm = &snat_main; + int rc, error = 0; + + fail_if_disabled (); + + rc = nat44_ed_del_static_mappings (); + if (rc) + error = VNET_API_ERROR_BUG; + + rc = nat44_ed_del_addresses (); + if (rc) + error = VNET_API_ERROR_BUG; + + rc = nat44_ed_del_interfaces (); + if (rc) + error = VNET_API_ERROR_BUG; + + rc = nat44_ed_del_output_interfaces (); + if (rc) + error = VNET_API_ERROR_BUG; + + nat44_ed_del_vrf_tables (); vec_free (sm->max_translations_per_fib); + sm->max_translations_per_fib = 0; nat44_ed_db_free (); - nat44_addresses_free (&sm->addresses); - nat44_addresses_free (&sm->twice_nat_addresses); - - vec_free (sm->to_resolve); - vec_free (sm->auto_add_sw_if_indices); - vec_free (sm->auto_add_sw_if_indices_twice_nat); + clib_memset (&sm->rconfig, 0, sizeof (sm->rconfig)); - sm->to_resolve = 0; - sm->auto_add_sw_if_indices = 0; - sm->auto_add_sw_if_indices_twice_nat = 0; + nat_affinity_disable (); sm->forwarding_enabled = 0; - sm->enabled = 0; - clib_memset (&sm->rconfig, 0, sizeof (sm->rconfig)); - return 0; + return error; } void @@ -2429,11 +2756,12 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, if (m) return m; - /* Try address only mapping */ + // try address only mapping m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, match_fib_index, 0); if (m) return m; + // default static mapping fib index (based on configuration) if (sm->inside_fib_index != match_fib_index) { m = nat44_ed_sm_i2o_lookup (sm, match_addr, match_port, @@ -2441,12 +2769,13 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, if (m) return m; - /* Try address only mapping */ + // try address only mapping m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, sm->inside_fib_index, 0); if (m) return m; } + // TODO: this specific use case may be deprecated (needs testing) if (sm->outside_fib_index != match_fib_index) { m = nat44_ed_sm_i2o_lookup (sm, match_addr, match_port, @@ -2454,7 +2783,7 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, if (m) return m; - /* Try address only mapping */ + // try address only mapping m = nat44_ed_sm_i2o_lookup (sm, match_addr, 0, sm->outside_fib_index, 0); if (m) @@ -2468,7 +2797,7 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, if (m) return m; - /* Try address only mapping */ + // try address only mapping m = nat44_ed_sm_o2i_lookup (sm, match_addr, 0, 0, 0); if (m) return m; @@ -2477,15 +2806,16 @@ nat44_ed_sm_match (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, } int -snat_static_mapping_match (vlib_main_t *vm, snat_main_t *sm, - ip4_address_t match_addr, u16 match_port, - u32 match_fib_index, ip_protocol_t match_protocol, +snat_static_mapping_match (vlib_main_t *vm, ip4_address_t match_addr, + u16 match_port, u32 match_fib_index, + ip_protocol_t match_protocol, ip4_address_t *mapping_addr, u16 *mapping_port, u32 *mapping_fib_index, int by_external, u8 *is_addr_only, twice_nat_type_t *twice_nat, lb_nat_type_t *lb, ip4_address_t *ext_host_addr, u8 *is_identity_nat, snat_static_mapping_t **out) { + snat_main_t *sm = &snat_main; snat_static_mapping_t *m; u32 rand, lo = 0, hi, mid, *tmp = 0, i; nat44_lb_addr_port_t *local; @@ -2629,7 +2959,7 @@ nat44_ed_get_in2out_worker_index (vlib_buffer_t *b, ip4_header_t *ip, if (PREDICT_FALSE (is_output)) { fib_index = sm->outside_fib_index; - nat_outside_fib_t *outside_fib; + nat_fib_t *outside_fib; fib_node_index_t fei = FIB_NODE_INDEX_INVALID; fib_prefix_t pfx = { .fp_proto = FIB_PROTOCOL_IP4, @@ -2715,7 +3045,9 @@ nat44_ed_get_in2out_worker_index (vlib_buffer_t *b, ip4_header_t *ip, } hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) + - (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24); + (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24) + + rx_fib_index + (rx_fib_index >> 8) + (rx_fib_index >> 16) + + (rx_fib_index >> 24); if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers)))) next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)]; @@ -2825,7 +3157,7 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, { udp_header_t *udp = ip4_next_header (ip); icmp46_header_t *icmp = (icmp46_header_t *) udp; - icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1); + nat_icmp_echo_header_t *echo = (nat_icmp_echo_header_t *) (icmp + 1); if (!icmp_type_is_error_message (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)) port = vnet_buffer (b)->ip.reass.l4_src_port; @@ -2839,13 +3171,13 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, { case IP_PROTOCOL_ICMP: icmp = (icmp46_header_t *) l4_header; - echo = (icmp_echo_header_t *) (icmp + 1); + echo = (nat_icmp_echo_header_t *) (icmp + 1); port = echo->identifier; break; case IP_PROTOCOL_UDP: /* breakthrough */ case IP_PROTOCOL_TCP: - port = ((tcp_udp_header_t *) l4_header)->src_port; + port = ((nat_tcp_udp_header_t *) l4_header)->src_port; break; default: next_worker_index = vlib_get_thread_index (); @@ -2879,9 +3211,7 @@ nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, } /* worker by outside port */ - next_worker_index = sm->first_worker_index; - next_worker_index += - sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread]; + next_worker_index = get_thread_idx_by_port (clib_net_to_host_u16 (port)); done: nat_elog_debug_handoff (sm, "HANDOFF OUT2IN", next_worker_index, @@ -2910,16 +3240,12 @@ nat44_set_session_limit (u32 session_limit, u32 vrf_id) { snat_main_t *sm = &snat_main; u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id); - u32 len = vec_len (sm->max_translations_per_fib); - if (len <= fib_index) - { - vec_validate (sm->max_translations_per_fib, fib_index + 1); - - for (; len < vec_len (sm->max_translations_per_fib); len++) - sm->max_translations_per_fib[len] = sm->max_translations_per_thread; - } + if (~0 == fib_index) + return -1; + vec_validate_init_empty (sm->max_translations_per_fib, fib_index, + sm->max_translations_per_thread); sm->max_translations_per_fib[fib_index] = session_limit; return 0; } @@ -2933,8 +3259,8 @@ nat44_update_session_limit (u32 session_limit, u32 vrf_id) return 1; sm->max_translations_per_thread = nat44_get_max_session_limit (); - stat_segment_set_state_counter (sm->max_cfg_sessions_gauge, - sm->max_translations_per_thread); + vlib_stats_set_gauge (sm->max_cfg_sessions_gauge, + sm->max_translations_per_thread); sm->translation_buckets = nat_calc_bihash_buckets (sm->max_translations_per_thread); @@ -2944,11 +3270,11 @@ nat44_update_session_limit (u32 session_limit, u32 vrf_id) } static void -nat44_ed_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations, - u32 translation_buckets) +nat44_ed_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations) { dlist_elt_t *head; + pool_alloc (tsm->per_vrf_sessions_pool, translations); pool_alloc (tsm->sessions, translations); pool_alloc (tsm->lru_pool, translations); @@ -2974,7 +3300,7 @@ nat44_ed_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations, } static void -reinit_ed_flow_hash () +nat44_ed_flow_hash_init () { snat_main_t *sm = &snat_main; // we expect 2 flows per session, so multiply translation_buckets by 2 @@ -2985,20 +3311,16 @@ reinit_ed_flow_hash () } static void -nat44_ed_db_init (u32 translations, u32 translation_buckets) +nat44_ed_db_init () { snat_main_t *sm = &snat_main; snat_main_per_thread_data_t *tsm; - reinit_ed_flow_hash (); + nat44_ed_flow_hash_init (); - if (sm->pat) + vec_foreach (tsm, sm->per_thread_data) { - vec_foreach (tsm, sm->per_thread_data) - { - nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread, - sm->translation_buckets); - } + nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread); } } @@ -3007,119 +3329,131 @@ nat44_ed_worker_db_free (snat_main_per_thread_data_t *tsm) { pool_free (tsm->lru_pool); pool_free (tsm->sessions); - vec_free (tsm->per_vrf_sessions_vec); + pool_free (tsm->per_vrf_sessions_pool); } static void -nat44_ed_db_free () +nat44_ed_flow_hash_free () { snat_main_t *sm = &snat_main; - snat_main_per_thread_data_t *tsm; - pool_free (sm->static_mappings); clib_bihash_free_16_8 (&sm->flow_hash); +} - if (sm->pat) +static void +nat44_ed_db_free () +{ + snat_main_t *sm = &snat_main; + snat_main_per_thread_data_t *tsm; + + vec_foreach (tsm, sm->per_thread_data) { - vec_foreach (tsm, sm->per_thread_data) - { - nat44_ed_worker_db_free (tsm); - } + nat44_ed_worker_db_free (tsm); } + + nat44_ed_flow_hash_free (); } void nat44_ed_sessions_clear () { snat_main_t *sm = &snat_main; - snat_main_per_thread_data_t *tsm; - - reinit_ed_flow_hash (); - - if (sm->pat) - { - vec_foreach (tsm, sm->per_thread_data) - { - nat44_ed_worker_db_free (tsm); - nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread, - sm->translation_buckets); - } - } + nat44_ed_db_free (); + nat44_ed_db_init (); vlib_zero_simple_counter (&sm->total_sessions, 0); } static void -nat44_ed_add_del_static_mapping_addr_only_cb ( - ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, - u32 address_length, u32 if_address_index, u32 is_delete) +nat44_ed_add_del_static_mapping_cb (ip4_main_t *im, uword opaque, + u32 sw_if_index, ip4_address_t *address, + u32 address_length, u32 if_address_index, + u32 is_delete) { - snat_static_map_resolve_t *rp; + snat_static_mapping_resolve_t *rp; snat_main_t *sm = &snat_main; - snat_static_mapping_t *m; - int i, rv = 0, match = 0; + int rv = 0; if (!sm->enabled) { return; } - // find first addr_only resolve record by sw_if_index - for (i = 0; i < vec_len (sm->to_resolve); i++) + vec_foreach (rp, sm->sm_to_resolve) { - rp = sm->to_resolve + i; - if (is_sm_addr_only (rp->flags) && rp->sw_if_index == sw_if_index) + if (sw_if_index == rp->sw_if_index) { - match = 1; - break; + if (is_delete) + { + if (rp->is_resolved) + { + rv = nat44_ed_del_static_mapping_internal ( + rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, + rp->vrf_id, rp->flags); + if (rv) + { + nat_log_err ("ed del static mapping failed"); + } + else + { + rp->is_resolved = 0; + } + } + } + else + { + if (!rp->is_resolved) + { + rv = nat44_ed_add_static_mapping_internal ( + rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, + rp->vrf_id, ~0, rp->flags, rp->pool_addr, rp->tag); + if (rv) + { + nat_log_err ("ed add static mapping failed"); + } + else + { + rp->is_resolved = 1; + } + } + } } } - if (!match) - { - return; - } +} - m = nat44_ed_sm_o2i_lookup ( - sm, *address, is_sm_addr_only (rp->flags) ? 0 : rp->e_port, 0, rp->proto); +static int +nat44_ed_get_addr_resolve_record (u32 sw_if_index, u8 twice_nat, int *out) +{ + snat_main_t *sm = &snat_main; + snat_address_resolve_t *rp; + int i; - if (is_delete) + for (i = 0; i < vec_len (sm->addr_to_resolve); i++) { - if (m) - { - rv = nat44_ed_del_static_mapping (rp->l_addr, address[0], rp->l_port, - rp->e_port, rp->proto, rp->vrf_id, - ~0, rp->flags); - } - } - else - { - if (!m) + rp = sm->addr_to_resolve + i; + + if ((rp->sw_if_index == sw_if_index) && (rp->is_twice_nat == twice_nat)) { - rv = nat44_ed_add_static_mapping ( - rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, - rp->vrf_id, ~0, rp->flags, rp->pool_addr, rp->tag); + if (out) + { + *out = i; + } + return 0; } - // else: don't trip over lease renewal, static config - } - if (rv) - { - nat_elog_notice_X1 (sm, "nat44_ed_del_static_mapping returned %d", "i4", - rv); } + return 1; } - -static_always_inline int -is_sw_if_index_reg_for_auto_resolve (u32 *sw_if_indices, u32 sw_if_index) +static int +nat44_ed_del_addr_resolve_record (u32 sw_if_index, u8 twice_nat) { - u32 *i; - vec_foreach (i, sw_if_indices) + snat_main_t *sm = &snat_main; + int i; + if (!nat44_ed_get_addr_resolve_record (sw_if_index, twice_nat, &i)) { - if (*i == sw_if_index) - { - return 1; - } + vec_del1 (sm->addr_to_resolve, i); + return 0; } - return 0; + return 1; } static void @@ -3129,69 +3463,78 @@ nat44_ed_add_del_interface_address_cb (ip4_main_t *im, uword opaque, u32 if_address_index, u32 is_delete) { snat_main_t *sm = &snat_main; - snat_static_map_resolve_t *rp; - snat_address_t *addresses = sm->addresses; + snat_address_resolve_t *arp; + snat_address_t *ap; u8 twice_nat = 0; - int rv, i; + int i, rv; if (!sm->enabled) { return; } - if (!is_sw_if_index_reg_for_auto_resolve (sm->auto_add_sw_if_indices, - sw_if_index)) + if (nat44_ed_get_addr_resolve_record (sw_if_index, twice_nat, &i)) { - if (!is_sw_if_index_reg_for_auto_resolve ( - sm->auto_add_sw_if_indices_twice_nat, sw_if_index)) + twice_nat = 1; + if (nat44_ed_get_addr_resolve_record (sw_if_index, twice_nat, &i)) { + u32 fib_index = + ip4_fib_table_get_index_for_sw_if_index (sw_if_index); + vec_foreach (ap, sm->addresses) + { + if ((fib_index == ap->fib_index) && + (address->as_u32 == ap->addr.as_u32)) + { + if (!is_delete) + { + ap->addr_len = address_length; + ap->sw_if_index = sw_if_index; + ap->net.as_u32 = + ap->addr.as_u32 & ip4_main.fib_masks[ap->addr_len]; + + nat_log_debug ( + "pool addr %U binds to -> sw_if_idx: %u net: %U/%u", + format_ip4_address, &ap->addr, ap->sw_if_index, + format_ip4_address, &ap->net, ap->addr_len); + } + else + { + ap->addr_len = ~0; + } + break; + } + } return; } - else - { - addresses = sm->twice_nat_addresses; - twice_nat = 1; - } } + arp = sm->addr_to_resolve + i; + if (!is_delete) { - // don't trip over lease renewal, static config - for (i = 0; i < vec_len (addresses); i++) + if (arp->is_resolved) { - if (addresses[i].addr.as_u32 == address->as_u32) - { - return; - } + return; } - (void) nat44_ed_add_address (address, ~0, twice_nat); - - // scan static mapping switch address resolution record vector - for (i = 0; i < vec_len (sm->to_resolve); i++) + rv = nat44_ed_add_address (address, ~0, arp->is_twice_nat); + if (0 == rv) { - rp = sm->to_resolve + i; - if (is_sm_addr_only (rp->flags)) - { - continue; - } - if (rp->sw_if_index == sw_if_index) - { - rv = nat44_ed_add_static_mapping ( - rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, - rp->vrf_id, sw_if_index, rp->flags, rp->pool_addr, rp->tag); - if (rv) - { - nat_elog_notice_X1 (sm, "add_static_mapping returned %d", - "i4", rv); - } - } + arp->is_resolved = 1; } } else { - // remove all static mapping records - (void) nat44_ed_del_address (address[0], 1, twice_nat); + if (!arp->is_resolved) + { + return; + } + + rv = nat44_ed_del_address (address[0], arp->is_twice_nat); + if (0 == rv) + { + arp->is_resolved = 0; + } } } @@ -3201,34 +3544,35 @@ nat44_ed_add_interface_address (u32 sw_if_index, u8 twice_nat) snat_main_t *sm = &snat_main; ip4_main_t *ip4_main = sm->ip4_main; ip4_address_t *first_int_addr; - u32 *auto_add_sw_if_indices = twice_nat ? - sm->auto_add_sw_if_indices_twice_nat : - sm->auto_add_sw_if_indices; - int i; + snat_address_resolve_t *ap; + int rv; - for (i = 0; i < vec_len (auto_add_sw_if_indices); i++) + if (!sm->enabled) { - if (auto_add_sw_if_indices[i] == sw_if_index) - { - return VNET_API_ERROR_VALUE_EXIST; - } + nat_log_err ("nat44 is disabled"); + return VNET_API_ERROR_UNSUPPORTED; } - // add to the auto-address list - if (twice_nat) - { - vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index); - } - else + if (!nat44_ed_get_addr_resolve_record (sw_if_index, twice_nat, 0)) { - vec_add1 (sm->auto_add_sw_if_indices, sw_if_index); + return VNET_API_ERROR_VALUE_EXIST; } - // if the address is already bound - or static - add it now + vec_add2 (sm->addr_to_resolve, ap, 1); + ap->sw_if_index = sw_if_index; + ap->is_twice_nat = twice_nat; + ap->is_resolved = 0; + first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0); if (first_int_addr) { - (void) nat44_ed_add_address (first_int_addr, ~0, twice_nat); + rv = nat44_ed_add_address (first_int_addr, ~0, twice_nat); + if (0 != rv) + { + nat44_ed_del_addr_resolve_record (sw_if_index, twice_nat); + return rv; + } + ap->is_resolved = 1; } return 0; @@ -3240,62 +3584,25 @@ nat44_ed_del_interface_address (u32 sw_if_index, u8 twice_nat) snat_main_t *sm = &snat_main; ip4_main_t *ip4_main = sm->ip4_main; ip4_address_t *first_int_addr; - snat_static_map_resolve_t *rp; - u32 *indices_to_delete = 0; - int i, j; - u32 *auto_add_sw_if_indices; if (!sm->enabled) { + nat_log_err ("nat44 is disabled"); return VNET_API_ERROR_UNSUPPORTED; } - auto_add_sw_if_indices = twice_nat ? sm->auto_add_sw_if_indices_twice_nat : - sm->auto_add_sw_if_indices; - - for (i = 0; i < vec_len (auto_add_sw_if_indices); i++) + if (nat44_ed_del_addr_resolve_record (sw_if_index, twice_nat)) { - if (auto_add_sw_if_indices[i] == sw_if_index) - { - first_int_addr = - ip4_interface_first_address (ip4_main, sw_if_index, 0); - if (first_int_addr) - { - // remove all static mapping records - (void) nat44_ed_del_address (first_int_addr[0], 1, twice_nat); - } - else - { - for (j = 0; j < vec_len (sm->to_resolve); j++) - { - rp = sm->to_resolve + j; - if (rp->sw_if_index == sw_if_index) - { - vec_add1 (indices_to_delete, j); - } - } - if (vec_len (indices_to_delete)) - { - for (j = vec_len (indices_to_delete) - 1; j >= 0; j--) - { - vec_del1 (sm->to_resolve, j); - } - vec_free (indices_to_delete); - } - } + return VNET_API_ERROR_NO_SUCH_ENTRY; + } - if (twice_nat) - { - vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i); - } - else - { - vec_del1 (sm->auto_add_sw_if_indices, i); - } - return 0; - } + first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0); + if (first_int_addr) + { + return nat44_ed_del_address (first_int_addr[0], twice_nat); } - return VNET_API_ERROR_NO_SUCH_ENTRY; + + return 0; } int @@ -3528,7 +3835,7 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, return NAT_ED_TRNSL_ERR_TRANSLATION_FAILED; icmp46_header_t *icmp = ip4_next_header (ip); - icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1); + nat_icmp_echo_header_t *echo = (nat_icmp_echo_header_t *) (icmp + 1); if ((!vnet_buffer (b)->ip.reass.is_non_first_fragment)) { @@ -3544,7 +3851,7 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, { ip_csum_t sum = icmp->checksum; sum = ip_csum_update (sum, echo->identifier, f->rewrite.icmp_id, - icmp_echo_header_t, + nat_icmp_echo_header_t, identifier /* changed member */); echo->identifier = f->rewrite.icmp_id; icmp->checksum = ip_csum_fold (sum); @@ -3624,6 +3931,9 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, icmp->checksum = new_icmp_sum; break; case IP_PROTOCOL_ICMP: + nat_6t_flow_ip4_translate (sm, b, inner_ip, f, inner_proto, + 1 /* is_icmp_inner_ip4 */, + 0 /* skip_saddr_rewrite */); if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE) { icmp46_header_t *inner_icmp = ip4_next_header (inner_ip); @@ -3631,19 +3941,21 @@ nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, { return NAT_ED_TRNSL_ERR_PACKET_TRUNCATED; } - icmp_echo_header_t *inner_echo = - (icmp_echo_header_t *) (inner_icmp + 1); + nat_icmp_echo_header_t *inner_echo = + (nat_icmp_echo_header_t *) (inner_icmp + 1); if (f->rewrite.icmp_id != inner_echo->identifier) { ip_csum_t sum = icmp->checksum; - sum = ip_csum_update ( - sum, inner_echo->identifier, f->rewrite.icmp_id, - icmp_echo_header_t, identifier /* changed member */); + sum = ip_csum_update (sum, inner_echo->identifier, + f->rewrite.icmp_id, + nat_icmp_echo_header_t, + identifier /* changed member */); icmp->checksum = ip_csum_fold (sum); ip_csum_t inner_sum = inner_icmp->checksum; inner_sum = ip_csum_update ( sum, inner_echo->identifier, f->rewrite.icmp_id, - icmp_echo_header_t, identifier /* changed member */); + nat_icmp_echo_header_t, + identifier /* changed member */); inner_icmp->checksum = ip_csum_fold (inner_sum); inner_echo->identifier = f->rewrite.icmp_id; } @@ -3715,110 +4027,7 @@ nat_6t_flow_buf_translate_o2i (vlib_main_t *vm, snat_main_t *sm, 0 /* is_i2o */); } -u8 * -format_nat_6t (u8 *s, va_list *args) -{ - nat_6t_t *t = va_arg (*args, nat_6t_t *); - - s = format (s, "saddr %U sport %u daddr %U dport %u proto %U fib_idx %u", - format_ip4_address, t->saddr.as_u8, - clib_net_to_host_u16 (t->sport), format_ip4_address, - t->daddr.as_u8, clib_net_to_host_u16 (t->dport), - format_ip_protocol, t->proto, t->fib_index); - return s; -} - -u8 * -format_nat_ed_translation_error (u8 *s, va_list *args) -{ - nat_translation_error_e e = va_arg (*args, nat_translation_error_e); - - switch (e) - { - case NAT_ED_TRNSL_ERR_SUCCESS: - s = format (s, "success"); - break; - case NAT_ED_TRNSL_ERR_TRANSLATION_FAILED: - s = format (s, "translation-failed"); - break; - case NAT_ED_TRNSL_ERR_FLOW_MISMATCH: - s = format (s, "flow-mismatch"); - break; - case NAT_ED_TRNSL_ERR_PACKET_TRUNCATED: - s = format (s, "packet-truncated"); - break; - case NAT_ED_TRNSL_ERR_INNER_IP_CORRUPT: - s = format (s, "inner-ip-corrupted"); - break; - case NAT_ED_TRNSL_ERR_INVALID_CSUM: - s = format (s, "invalid-checksum"); - break; - } - return s; -} - -u8 * -format_nat_6t_flow (u8 *s, va_list *args) -{ - nat_6t_flow_t *f = va_arg (*args, nat_6t_flow_t *); - - s = format (s, "match: %U ", format_nat_6t, &f->match); - int r = 0; - if (f->ops & NAT_FLOW_OP_SADDR_REWRITE) - { - s = format (s, "rewrite: saddr %U ", format_ip4_address, - f->rewrite.saddr.as_u8); - r = 1; - } - if (f->ops & NAT_FLOW_OP_SPORT_REWRITE) - { - if (!r) - { - s = format (s, "rewrite: "); - r = 1; - } - s = format (s, "sport %u ", clib_net_to_host_u16 (f->rewrite.sport)); - } - if (f->ops & NAT_FLOW_OP_DADDR_REWRITE) - { - if (!r) - { - s = format (s, "rewrite: "); - r = 1; - } - s = format (s, "daddr %U ", format_ip4_address, f->rewrite.daddr.as_u8); - } - if (f->ops & NAT_FLOW_OP_DPORT_REWRITE) - { - if (!r) - { - s = format (s, "rewrite: "); - r = 1; - } - s = format (s, "dport %u ", clib_net_to_host_u16 (f->rewrite.dport)); - } - if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE) - { - if (!r) - { - s = format (s, "rewrite: "); - r = 1; - } - s = format (s, "icmp-id %u ", clib_net_to_host_u16 (f->rewrite.icmp_id)); - } - if (f->ops & NAT_FLOW_OP_TXFIB_REWRITE) - { - if (!r) - { - s = format (s, "rewrite: "); - r = 1; - } - s = format (s, "txfib %u ", f->rewrite.fib_index); - } - return s; -} - -static inline void +static_always_inline void nat_syslog_nat44_sess (u32 ssubix, u32 sfibix, ip4_address_t *isaddr, u16 isport, ip4_address_t *xsaddr, u16 xsport, ip4_address_t *idaddr, u16 idport, @@ -3892,7 +4101,49 @@ nat_syslog_nat44_sdel (u32 ssubix, u32 sfibix, ip4_address_t *isaddr, idaddr, idport, xdaddr, xdport, proto, 0, is_twicenat); } +__clib_export void +nat44_original_dst_lookup (ip4_address_t *i2o_src, u16 i2o_src_port, + ip4_address_t *i2o_dst, u16 i2o_dst_port, + ip_protocol_t proto, u32 *original_dst, + u16 *original_dst_port) +{ + snat_main_per_thread_data_t *tsm; + snat_main_t *sm = &snat_main; + u32 fib_index = 0; + snat_session_t *s; + ip4_header_t ip; + ip.src_address.as_u32 = i2o_src->as_u32; + fib_index = fib_table_find (FIB_PROTOCOL_IP4, 0); + + if (sm->num_workers > 1) + { + tsm = vec_elt_at_index ( + sm->per_thread_data, + nat44_ed_get_in2out_worker_index (0, &ip, fib_index, 0)); + } + else + { + tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); + } + + /* query */ + clib_bihash_kv_16_8_t kv = { 0 }, value; + init_ed_k (&kv, i2o_src->as_u32, i2o_src_port, i2o_dst->as_u32, i2o_dst_port, + fib_index, proto); + if (tsm->sessions == NULL || + clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value)) + { + return; + } + s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value)); + if (s) + { + *original_dst = s->i2o.rewrite.saddr.as_u32; + *original_dst_port = s->i2o.rewrite.sport; + } + return; +} /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/nat/nat44-ed/nat44_ed.h b/src/plugins/nat/nat44-ed/nat44_ed.h index 9fb34aa45f1..706511475cf 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed.h +++ b/src/plugins/nat/nat44-ed/nat44_ed.h @@ -12,10 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @file nat.c - * NAT plugin global declarations - */ + #ifndef __included_nat44_ed_h__ #define __included_nat44_ed_h__ @@ -44,6 +41,11 @@ * as if there were no free ports available to conserve resources */ #define ED_PORT_ALLOC_ATTEMPTS (10) +/* system ports range is 0-1023, first user port is 1024 per + * https://www.rfc-editor.org/rfc/rfc6335#section-6 + */ +#define ED_USER_PORT_OFFSET 1024 + /* NAT buffer flags */ #define SNAT_FLAG_HAIRPINNING (1 << 0) @@ -63,16 +65,9 @@ typedef enum nat44_config_flags_t_ typedef struct { - /* nat44 plugin features */ - u8 static_mapping_only; - u8 connection_tracking; - u32 inside_vrf; u32 outside_vrf; - - /* maximum number of sessions */ u32 sessions; - } nat44_config_t; typedef enum @@ -96,46 +91,12 @@ typedef struct u32 arc_next_index; } nat_pre_trace_t; -/* External address and port allocation modes */ -#define foreach_nat_addr_and_port_alloc_alg \ - _(0, DEFAULT, "default") \ - _(1, MAPE, "map-e") \ - _(2, RANGE, "port-range") - -typedef enum -{ -#define _(v, N, s) NAT_ADDR_AND_PORT_ALLOC_ALG_##N = v, - foreach_nat_addr_and_port_alloc_alg -#undef _ -} nat_addr_and_port_alloc_alg_t; - -/* Session state */ -#define foreach_snat_session_state \ - _(0, UNKNOWN, "unknown") \ - _(1, UDP_ACTIVE, "udp-active") \ - _(2, TCP_SYN_SENT, "tcp-syn-sent") \ - _(3, TCP_ESTABLISHED, "tcp-established") \ - _(4, TCP_FIN_WAIT, "tcp-fin-wait") \ - _(5, TCP_CLOSE_WAIT, "tcp-close-wait") \ - _(6, TCP_CLOSING, "tcp-closing") \ - _(7, TCP_LAST_ACK, "tcp-last-ack") \ - _(8, TCP_CLOSED, "tcp-closed") \ - _(9, ICMP_ACTIVE, "icmp-active") - -typedef enum -{ -#define _(v, N, s) SNAT_SESSION_##N = v, - foreach_snat_session_state -#undef _ -} snat_session_state_t; - #define foreach_nat_in2out_ed_error \ _ (UNSUPPORTED_PROTOCOL, "unsupported protocol") \ _ (OUT_OF_PORTS, "out of ports") \ _ (BAD_ICMP_TYPE, "unsupported ICMP type") \ _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \ _ (NON_SYN, "non-SYN packet try to create session") \ - _ (TCP_CLOSED, "drops due to TCP in transitory timeout") \ _ (TRNSL_FAILED, "couldn't translate packet") typedef enum @@ -165,15 +126,39 @@ typedef enum NAT_OUT2IN_ED_N_ERROR, } nat_out2in_ed_error_t; +typedef enum +{ + NAT44_ED_TCP_FLAG_FIN = 0, + NAT44_ED_TCP_FLAG_SYN, + NAT44_ED_TCP_FLAG_RST, + NAT44_ED_TCP_FLAG_ACK, + NAT44_ED_TCP_N_FLAG, +} nat44_ed_tcp_flag_e; + +typedef enum +{ + NAT44_ED_DIR_I2O = 0, + NAT44_ED_DIR_O2I, + NAT44_ED_N_DIR, +} nat44_ed_dir_e; /* Endpoint dependent TCP session state */ -#define NAT44_SES_I2O_FIN 1 -#define NAT44_SES_O2I_FIN 2 -#define NAT44_SES_I2O_FIN_ACK 4 -#define NAT44_SES_O2I_FIN_ACK 8 -#define NAT44_SES_I2O_SYN 16 -#define NAT44_SES_O2I_SYN 32 -#define NAT44_SES_RST 64 +typedef enum +{ + NAT44_ED_TCP_STATE_CLOSED = 0, + NAT44_ED_TCP_STATE_ESTABLISHED, + NAT44_ED_TCP_STATE_CLOSING, + NAT44_ED_TCP_N_STATE, +} nat44_ed_tcp_state_e; + +format_function_t format_ed_session_kvp; +format_function_t format_snat_session; +format_function_t format_snat_static_mapping; +format_function_t format_snat_static_map_to_resolve; +format_function_t format_nat_ed_translation_error; +format_function_t format_nat_6t_flow; +format_function_t format_nat_6t; +format_function_t format_nat44_ed_tcp_state; /* Session flags */ #define SNAT_SESSION_FLAG_STATIC_MAPPING (1 << 0) @@ -345,10 +330,8 @@ typedef CLIB_PACKED(struct u16 ext_host_nat_port; /* TCP session state */ - u8 state; - u32 i2o_fin_seq; - u32 o2i_fin_seq; - u64 tcp_closed_timestamp; + u8 tcp_flags[NAT44_ED_N_DIR]; + nat44_ed_tcp_state_e tcp_state; /* per vrf sessions index */ u32 per_vrf_sessions_index; @@ -359,23 +342,14 @@ typedef CLIB_PACKED(struct typedef struct { ip4_address_t addr; + ip4_address_t net; + u32 sw_if_index; u32 fib_index; + u32 addr_len; } snat_address_t; typedef struct { - u32 fib_index; - u32 ref_count; -} nat_fib_t; - -typedef struct -{ - u32 fib_index; - u32 refcount; -} nat_outside_fib_t; - -typedef struct -{ /* backend IP address */ ip4_address_t addr; /* backend port number */ @@ -447,6 +421,7 @@ typedef struct typedef struct { + u8 is_resolved; ip4_address_t l_addr; ip4_address_t pool_addr; u16 l_port; @@ -456,7 +431,21 @@ typedef struct ip_protocol_t proto; u32 flags; u8 *tag; -} snat_static_map_resolve_t; +} snat_static_mapping_resolve_t; + +typedef struct +{ + u8 is_resolved; + u8 is_twice_nat; + u32 sw_if_index; +} snat_address_resolve_t; + +typedef struct +{ + u32 count; + u32 sw_if_index; + ip4_address_t addr; +} snat_fib_entry_reg_t; typedef struct { @@ -480,7 +469,7 @@ typedef struct /* real thread index */ u32 thread_index; - per_vrf_sessions_t *per_vrf_sessions_vec; + per_vrf_sessions_t *per_vrf_sessions_pool; } snat_main_per_thread_data_t; @@ -491,12 +480,24 @@ u32 nat44_ed_get_in2out_worker_index (vlib_buffer_t *b, ip4_header_t *ip, u32 nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index, u8 is_output); -/* Return worker thread index for given packet */ -/* NAT address and port allocation function */ -typedef int (nat_alloc_out_addr_and_port_function_t) ( - snat_address_t *addresses, u32 fib_index, u32 thread_index, - ip_protocol_t proto, ip4_address_t *addr, u16 *port, u16 port_per_thread, - u32 snat_thread_index); +typedef struct nat_fib_s +{ + u32 fib_index; + u32 ref_count; +} nat_fib_t; + +typedef struct vrf_route_s +{ + u32 vrf_id; + u32 fib_index; +} vrf_route_t; + +typedef struct vrf_table_s +{ + u32 table_vrf_id; + u32 table_fib_index; + vrf_route_t *routes; +} vrf_table_t; typedef struct snat_main_s { @@ -519,6 +520,21 @@ typedef struct snat_main_s /* Endpoint dependent lookup table */ clib_bihash_16_8_t flow_hash; + // vector of fibs + nat_fib_t *fibs; + + u32 inside_vrf_id; + u32 inside_fib_index; + + u32 outside_vrf_id; + u32 outside_fib_index; + + // vector of outside fibs + nat_fib_t *outside_fibs; + + // VRF routing table for dynamic sessions + vrf_table_t *vrf_tables; + /* Interface pool */ snat_interface_t *interfaces; snat_interface_t *output_feature_interfaces; @@ -530,30 +546,14 @@ typedef struct snat_main_s /* Vector of twice NAT addresses for external hosts */ snat_address_t *twice_nat_addresses; - /* sw_if_indices whose intfc addresses should be auto-added */ - u32 *auto_add_sw_if_indices; - u32 *auto_add_sw_if_indices_twice_nat; - - /* Address and port allocation function */ - nat_alloc_out_addr_and_port_function_t *alloc_addr_and_port; - /* Address and port allocation type */ - nat_addr_and_port_alloc_alg_t addr_and_port_alloc_alg; - /* Port set parameters (MAP-E) */ - u8 psid_offset; - u8 psid_length; - u16 psid; - /* Port range parameters */ - u16 start_port; - u16 end_port; - - /* vector of fibs */ - nat_fib_t *fibs; + /* first interface address should be auto-added */ + snat_address_resolve_t *addr_to_resolve; - /* vector of outside fibs */ - nat_outside_fib_t *outside_fibs; + /* vector of fib entries */ + snat_fib_entry_reg_t *fib_entry_reg; /* vector of interface address static mappings to resolve. */ - snat_static_map_resolve_t *to_resolve; + snat_static_mapping_resolve_t *sm_to_resolve; /* Randomize port allocation order */ u32 random_seed; @@ -563,20 +563,11 @@ typedef struct snat_main_s u32 fq_in2out_output_index; u32 fq_out2in_index; - u32 out2in_node_index; - u32 in2out_node_index; - u32 in2out_output_node_index; - nat44_config_t rconfig; - //nat44_config_t cconfig; /* If forwarding is enabled */ u8 forwarding_enabled; - /* static mapping config */ - u8 static_mapping_only; - u8 static_mapping_connection_tracking; - /* Is translation memory size calculated or user defined */ u8 translation_memory_size_set; @@ -584,11 +575,6 @@ typedef struct snat_main_s u32 max_translations_per_thread; u32 *max_translations_per_fib; - u32 outside_vrf_id; - u32 outside_fib_index; - u32 inside_vrf_id; - u32 inside_fib_index; - nat_timeouts_t timeouts; /* TCP MSS clamping */ @@ -641,24 +627,27 @@ typedef struct snat_main_s u8 log_level; /* convenience */ - api_main_t *api_main; ip4_main_t *ip4_main; - ip_lookup_main_t *ip4_lookup_main; fib_source_t fib_src_hi; fib_source_t fib_src_low; - /* pat - dynamic mapping enabled or conneciton tracking */ - u8 pat; - /* number of worker handoff frame queue elements */ u32 frame_queue_nelts; /* nat44 plugin enabled */ u8 enabled; - vnet_main_t *vnet_main; - + /* TCP session state machine table: + * first dimension is possible states + * second dimension is direction (in2out/out2in) + * third dimension is TCP flag (SYN, RST, FIN) + * + * value is next state to change to + */ + nat44_ed_tcp_state_e tcp_state_change_table[NAT44_ED_TCP_N_STATE] + [NAT44_ED_N_DIR] + [NAT44_ED_TCP_N_FLAG]; } snat_main_t; typedef struct @@ -673,32 +662,25 @@ typedef struct uword *cached_presence_by_ip4_address; } snat_runtime_t; +/* + * 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 + * value to NAT an echo request/reply. + */ + extern snat_main_t snat_main; -// nat pre ed next_node feature classification extern vlib_node_registration_t nat_default_node; extern vlib_node_registration_t nat_pre_in2out_node; extern vlib_node_registration_t nat_pre_out2in_node; -extern vlib_node_registration_t snat_in2out_node; -extern vlib_node_registration_t snat_in2out_output_node; -extern vlib_node_registration_t snat_out2in_node; -extern vlib_node_registration_t snat_in2out_worker_handoff_node; -extern vlib_node_registration_t snat_in2out_output_worker_handoff_node; -extern vlib_node_registration_t snat_out2in_worker_handoff_node; extern vlib_node_registration_t nat44_ed_in2out_node; extern vlib_node_registration_t nat44_ed_in2out_output_node; extern vlib_node_registration_t nat44_ed_out2in_node; -extern fib_source_t nat_fib_src_hi; -extern fib_source_t nat_fib_src_low; - -/* format functions */ -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_static_mapping_key; -format_function_t format_nat_addr_and_port_alloc_alg; +extern vlib_node_registration_t snat_in2out_worker_handoff_node; +extern vlib_node_registration_t snat_in2out_output_worker_handoff_node; +extern vlib_node_registration_t snat_out2in_worker_handoff_node; /** \brief Check if SNAT session is created from static mapping. @param s SNAT session @@ -780,16 +762,6 @@ nat44_ed_is_interface_outside (snat_interface_t *i) return i->flags & NAT_INTERFACE_FLAG_IS_OUTSIDE; } -/** \brief Check if NAT44 endpoint-dependent TCP session is closed. - @param s NAT session - @return true if session is closed -*/ -always_inline bool -nat44_is_ses_closed (snat_session_t *s) -{ - return s->state == 0xf; -} - /** \brief Check if client initiating TCP connection (received SYN from client) @param t TCP header @return true if client initiating TCP connection @@ -848,13 +820,10 @@ is_sm_switch_address (u32 f) return (f & NAT_SM_FLAG_SWITCH_ADDRESS); } -/* logging */ #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(...)\ @@ -873,10 +842,14 @@ int nat44_ed_add_output_interface (u32 sw_if_index); int nat44_ed_del_output_interface (u32 sw_if_index); int nat44_ed_add_address (ip4_address_t *addr, u32 vrf_id, u8 twice_nat); -int nat44_ed_del_address (ip4_address_t addr, u8 delete_sm, u8 twice_nat); +int nat44_ed_del_address (ip4_address_t addr, u8 twice_nat); int nat44_ed_add_interface_address (u32 sw_if_index, u8 twice_nat); int nat44_ed_del_interface_address (u32 sw_if_index, u8 twice_nat); +int nat44_ed_add_del_vrf_table (u32 table_vrf_id, bool is_add); +int nat44_ed_add_del_vrf_route (u32 table_vrf_id, u32 vrf_id, bool is_add); +void nat44_ed_del_vrf_tables (); + int nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, ip_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags, @@ -938,55 +911,18 @@ int nat44_update_session_limit (u32 session_limit, u32 vrf_id); void expire_per_vrf_sessions (u32 fib_index); -/** - * @brief Match NAT44 static mapping. - * - * @param key address and port to match - * @param addr external/local address of the matched mapping - * @param port port of the matched mapping - * @param fib_index fib index of the matched mapping - * @param by_external if 0 match by local address otherwise match by external - * address - * @param is_addr_only 1 if matched mapping is address only - * @param twice_nat matched mapping is twice NAT type - * @param lb 1 if matched mapping is load-balanced - * @param ext_host_addr external host address - * @param is_identity_nat 1 if indentity mapping - * @param out if !=0 set to pointer of the mapping structure - * - * @returns 0 if match found otherwise 1. - */ -int snat_static_mapping_match ( - vlib_main_t *vm, snat_main_t *sm, ip4_address_t match_addr, u16 match_port, - u32 match_fib_index, ip_protocol_t match_protocol, - ip4_address_t *mapping_addr, u16 *mapping_port, u32 *mapping_fib_index, - int by_external, u8 *is_addr_only, twice_nat_type_t *twice_nat, - lb_nat_type_t *lb, ip4_address_t *ext_host_addr, u8 *is_identity_nat, - snat_static_mapping_t **out); - -/* - * 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 - * value to NAT an echo request/reply. - */ - -typedef struct -{ - u16 identifier; - u16 sequence; -} icmp_echo_header_t; - -typedef struct -{ - u16 src_port, dst_port; -} tcp_udp_header_t; +int snat_static_mapping_match (vlib_main_t *vm, ip4_address_t match_addr, + u16 match_port, u32 match_fib_index, + ip_protocol_t match_protocol, + ip4_address_t *mapping_addr, u16 *mapping_port, + u32 *mapping_fib_index, int by_external, + u8 *is_addr_only, twice_nat_type_t *twice_nat, + lb_nat_type_t *lb, ip4_address_t *ext_host_addr, + u8 *is_identity_nat, + snat_static_mapping_t **out); u32 get_thread_idx_by_port (u16 e_port); -u8 *format_static_mapping_kvp (u8 *s, va_list *args); - -u8 *format_session_kvp (u8 *s, va_list *args); - u32 nat_calc_bihash_buckets (u32 n_elts); void nat44_addresses_free (snat_address_t **addresses); @@ -995,30 +931,8 @@ void nat44_ed_sessions_clear (); int nat44_ed_set_frame_queue_nelts (u32 frame_queue_nelts); -typedef enum -{ - NAT_ED_TRNSL_ERR_SUCCESS = 0, - NAT_ED_TRNSL_ERR_TRANSLATION_FAILED = 1, - NAT_ED_TRNSL_ERR_FLOW_MISMATCH = 2, - NAT_ED_TRNSL_ERR_PACKET_TRUNCATED = 3, - NAT_ED_TRNSL_ERR_INNER_IP_CORRUPT = 4, - NAT_ED_TRNSL_ERR_INVALID_CSUM = 5, -} nat_translation_error_e; - -nat_translation_error_e nat_6t_flow_buf_translate_i2o ( - vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, - nat_6t_flow_t *f, ip_protocol_t proto, int is_output_feature); - -nat_translation_error_e nat_6t_flow_buf_translate_o2i ( - vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, - nat_6t_flow_t *f, ip_protocol_t proto, int is_output_feature); - void nat_6t_l3_l4_csum_calc (nat_6t_flow_t *f); -format_function_t format_nat_ed_translation_error; -format_function_t format_nat_6t_flow; -format_function_t format_ed_session_kvp; - snat_static_mapping_t *nat44_ed_sm_i2o_lookup (snat_main_t *sm, ip4_address_t addr, u16 port, u32 fib_index, u8 proto); @@ -1039,6 +953,24 @@ void nat_syslog_nat44_sdel (u32 ssubix, u32 sfibix, ip4_address_t *isaddr, ip4_address_t *xdaddr, u16 xdport, u8 proto, u8 is_twicenat); +typedef enum +{ + NAT_ED_TRNSL_ERR_SUCCESS = 0, + NAT_ED_TRNSL_ERR_TRANSLATION_FAILED = 1, + NAT_ED_TRNSL_ERR_FLOW_MISMATCH = 2, + NAT_ED_TRNSL_ERR_PACKET_TRUNCATED = 3, + NAT_ED_TRNSL_ERR_INNER_IP_CORRUPT = 4, + NAT_ED_TRNSL_ERR_INVALID_CSUM = 5, +} nat_translation_error_e; + +nat_translation_error_e nat_6t_flow_buf_translate_i2o ( + vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, + nat_6t_flow_t *f, ip_protocol_t proto, int is_output_feature); + +nat_translation_error_e nat_6t_flow_buf_translate_o2i ( + vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, + nat_6t_flow_t *f, ip_protocol_t proto, int is_output_feature); + #endif /* __included_nat44_ed_h__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/nat44-ed/nat44_ed_api.c b/src/plugins/nat/nat44-ed/nat44_ed_api.c index 15059752ee7..b6c9d51d777 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_api.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_api.c @@ -31,6 +31,8 @@ #include <nat/nat44-ed/nat44_ed.api_enum.h> #include <nat/nat44-ed/nat44_ed.api_types.h> +#include <nat/nat44-ed/nat44_ed_inlines.h> + #define REPLY_MSG_ID_BASE sm->msg_id_base #include <vlibapi/api_helper_macros.h> @@ -47,15 +49,19 @@ vl_api_nat44_ed_plugin_enable_disable_t_handler ( if (mp->enable) { - c.static_mapping_only = mp->flags & NAT44_API_IS_STATIC_MAPPING_ONLY; - c.connection_tracking = mp->flags & NAT44_API_IS_CONNECTION_TRACKING; - - c.inside_vrf = ntohl (mp->inside_vrf); - c.outside_vrf = ntohl (mp->outside_vrf); - - c.sessions = ntohl (mp->sessions); + if ((mp->flags & NAT44_API_IS_STATIC_MAPPING_ONLY) || + (mp->flags & NAT44_API_IS_CONNECTION_TRACKING)) + { + rv = VNET_API_ERROR_UNSUPPORTED; + } + else + { + c.sessions = ntohl (mp->sessions); + c.inside_vrf = ntohl (mp->inside_vrf); + c.outside_vrf = ntohl (mp->outside_vrf); - rv = nat44_plugin_enable (c); + rv = nat44_plugin_enable (c); + } } else { @@ -171,21 +177,6 @@ vl_api_nat44_set_session_limit_t_handler (vl_api_nat44_set_session_limit_t * } static void -vl_api_nat_set_log_level_t_handler (vl_api_nat_set_log_level_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_nat_set_log_level_reply_t *rmp; - int rv = 0; - - if (sm->log_level > NAT_LOG_DEBUG) - rv = VNET_API_ERROR_UNSUPPORTED; - else - sm->log_level = mp->log_level; - - REPLY_MACRO (VL_API_NAT_SET_WORKERS_REPLY); -} - -static void vl_api_nat_ipfix_enable_disable_t_handler (vl_api_nat_ipfix_enable_disable_t * mp) { @@ -217,22 +208,6 @@ vl_api_nat_set_timeouts_t_handler (vl_api_nat_set_timeouts_t * mp) } static void -vl_api_nat_get_timeouts_t_handler (vl_api_nat_get_timeouts_t * mp) -{ - snat_main_t *sm = &snat_main; - vl_api_nat_get_timeouts_reply_t *rmp; - int rv = 0; - - REPLY_MACRO2 (VL_API_NAT_GET_TIMEOUTS_REPLY, - ({ - rmp->udp = htonl (sm->timeouts.udp); - rmp->tcp_established = htonl (sm->timeouts.tcp.established); - rmp->tcp_transitory = htonl (sm->timeouts.tcp.transitory); - rmp->icmp = htonl (sm->timeouts.icmp); - })) -} - -static void vl_api_nat_set_mss_clamping_t_handler (vl_api_nat_set_mss_clamping_t * mp) { snat_main_t *sm = &snat_main; @@ -275,12 +250,6 @@ static void int rv = 0; u32 *tmp; - if (sm->static_mapping_only) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - is_add = mp->is_add; twice_nat = mp->flags & NAT_API_IS_TWICE_NAT; @@ -308,7 +277,7 @@ static void } else { - rv = nat44_ed_del_address (this_addr, 0, twice_nat); + rv = nat44_ed_del_address (this_addr, twice_nat); } if (rv) @@ -431,145 +400,27 @@ vl_api_nat44_interface_dump_t_handler (vl_api_nat44_interface_dump_t * mp) } } -static_always_inline int -add_del_dummy_output_interface (u32 sw_if_index, u8 is_inside, u8 is_add) -{ - snat_main_t *sm = &snat_main; - snat_interface_t *i; - int rv = 1; - - pool_foreach (i, sm->output_feature_dummy_interfaces) - { - if (i->sw_if_index == sw_if_index) - { - if (!is_add) - { - pool_put (sm->output_feature_dummy_interfaces, i); - rv = 0; - } - goto done; - } - } - - if (is_add) - { - pool_get (sm->output_feature_dummy_interfaces, i); - i->sw_if_index = sw_if_index; - - if (is_inside) - { - i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE; - } - else - { - i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE; - } - - rv = 0; - } - -done: - return rv; -} - -static void - vl_api_nat44_interface_add_del_output_feature_t_handler - (vl_api_nat44_interface_add_del_output_feature_t * mp) -{ - vl_api_nat44_interface_add_del_output_feature_reply_t *rmp; - snat_main_t *sm = &snat_main; - u32 sw_if_index; - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - sw_if_index = ntohl (mp->sw_if_index); - - // register all interfaces in the dummy structure - rv = add_del_dummy_output_interface ( - sw_if_index, mp->flags & NAT_API_IS_INSIDE, mp->is_add); - - if (!(mp->flags & NAT_API_IS_INSIDE)) - { - if (mp->is_add) - { - rv = nat44_ed_add_output_interface (sw_if_index); - } - else - { - rv = nat44_ed_del_output_interface (sw_if_index); - } - } - - BAD_SW_IF_INDEX_LABEL; - REPLY_MACRO (VL_API_NAT44_INTERFACE_ADD_DEL_OUTPUT_FEATURE_REPLY); -} - -static void -send_nat44_interface_output_feature_details (snat_interface_t * i, - vl_api_registration_t * reg, - u32 context) -{ - vl_api_nat44_interface_output_feature_details_t *rmp; - snat_main_t *sm = &snat_main; - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - clib_memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = - ntohs (VL_API_NAT44_INTERFACE_OUTPUT_FEATURE_DETAILS + sm->msg_id_base); - rmp->sw_if_index = ntohl (i->sw_if_index); - rmp->context = context; - - if (nat44_ed_is_interface_inside (i)) - { - rmp->flags |= NAT_API_IS_INSIDE; - } - - vl_api_send_msg (reg, (u8 *) rmp); -} - -static void - vl_api_nat44_interface_output_feature_dump_t_handler - (vl_api_nat44_interface_output_feature_dump_t * mp) -{ - vl_api_registration_t *reg; - snat_main_t *sm = &snat_main; - snat_interface_t *i; - - reg = vl_api_client_index_to_registration (mp->client_index); - if (!reg) - return; - - pool_foreach (i, sm->output_feature_dummy_interfaces) - { - send_nat44_interface_output_feature_details (i, reg, mp->context); - } -} - static void vl_api_nat44_ed_add_del_output_interface_t_handler ( vl_api_nat44_ed_add_del_output_interface_t *mp) { vl_api_nat44_ed_add_del_output_interface_reply_t *rmp; snat_main_t *sm = &snat_main; - u32 sw_if_index; int rv = 0; - VALIDATE_SW_IF_INDEX (mp); - - sw_if_index = ntohl (mp->sw_if_index); + VALIDATE_SW_IF_INDEX_END (mp); if (mp->is_add) { - rv = nat44_ed_add_output_interface (sw_if_index); + rv = nat44_ed_add_output_interface (mp->sw_if_index); } else { - rv = nat44_ed_del_output_interface (sw_if_index); + rv = nat44_ed_del_output_interface (mp->sw_if_index); } - BAD_SW_IF_INDEX_LABEL; - REPLY_MACRO (VL_API_NAT44_ED_ADD_DEL_OUTPUT_INTERFACE_REPLY); +bad_sw_if_index: + REPLY_MACRO_END (VL_API_NAT44_ED_ADD_DEL_OUTPUT_INTERFACE_REPLY); } #define vl_endianfun @@ -591,7 +442,8 @@ send_nat44_ed_output_interface_details (u32 index, vl_api_registration_t *rp, /* Endian hack until apigen registers _details * endian functions */ - vl_api_nat44_ed_output_interface_details_t_endian (rmp); + vl_api_nat44_ed_output_interface_details_t_endian (rmp, + 1 /* to network */); rmp->_vl_msg_id = htons (rmp->_vl_msg_id); rmp->context = htonl (rmp->context); })); @@ -739,7 +591,7 @@ static void } sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index); - if (sw_if_index) + if (sw_if_index != ~0) { flags |= NAT_SM_FLAG_SWITCH_ADDRESS; } @@ -824,9 +676,8 @@ send_nat44_static_mapping_details (snat_static_mapping_t * m, } static void -send_nat44_static_map_resolve_details (snat_static_map_resolve_t * m, - vl_api_registration_t * reg, - u32 context) +send_nat44_static_map_resolve_details (snat_static_mapping_resolve_t *m, + vl_api_registration_t *reg, u32 context) { vl_api_nat44_static_mapping_details_t *rmp; snat_main_t *sm = &snat_main; @@ -869,7 +720,7 @@ vl_api_nat44_static_mapping_dump_t_handler (vl_api_nat44_static_mapping_dump_t vl_api_registration_t *reg; snat_main_t *sm = &snat_main; snat_static_mapping_t *m; - snat_static_map_resolve_t *rp; + snat_static_mapping_resolve_t *rp; int j; reg = vl_api_client_index_to_registration (mp->client_index); @@ -882,9 +733,9 @@ vl_api_nat44_static_mapping_dump_t_handler (vl_api_nat44_static_mapping_dump_t send_nat44_static_mapping_details (m, reg, mp->context); } - for (j = 0; j < vec_len (sm->to_resolve); j++) + for (j = 0; j < vec_len (sm->sm_to_resolve); j++) { - rp = sm->to_resolve + j; + rp = sm->sm_to_resolve + j; if (!is_sm_identity_nat (rp->flags)) send_nat44_static_map_resolve_details (rp, reg, mp->context); } @@ -976,8 +827,8 @@ send_nat44_identity_mapping_details (snat_static_mapping_t * m, int index, } static void -send_nat44_identity_map_resolve_details (snat_static_map_resolve_t * m, - vl_api_registration_t * reg, +send_nat44_identity_map_resolve_details (snat_static_mapping_resolve_t *m, + vl_api_registration_t *reg, u32 context) { vl_api_nat44_identity_mapping_details_t *rmp; @@ -1009,7 +860,7 @@ static void vl_api_registration_t *reg; snat_main_t *sm = &snat_main; snat_static_mapping_t *m; - snat_static_map_resolve_t *rp; + snat_static_mapping_resolve_t *rp; int j; reg = vl_api_client_index_to_registration (mp->client_index); @@ -1027,9 +878,9 @@ static void } } - for (j = 0; j < vec_len (sm->to_resolve); j++) + for (j = 0; j < vec_len (sm->sm_to_resolve); j++) { - rp = sm->to_resolve + j; + rp = sm->sm_to_resolve + j; if (is_sm_identity_nat (rp->flags)) send_nat44_identity_map_resolve_details (rp, reg, mp->context); } @@ -1045,12 +896,6 @@ static void u8 twice_nat; int rv = 0; - if (sm->static_mapping_only) - { - rv = VNET_API_ERROR_FEATURE_DISABLED; - goto send_reply; - } - VALIDATE_SW_IF_INDEX (mp); twice_nat = mp->flags & NAT_API_IS_TWICE_NAT; @@ -1066,7 +911,6 @@ static void BAD_SW_IF_INDEX_LABEL; -send_reply: REPLY_MACRO (VL_API_NAT44_ADD_DEL_INTERFACE_ADDR_REPLY); } @@ -1095,21 +939,18 @@ static void vl_api_nat44_interface_addr_dump_t_handler (vl_api_nat44_interface_addr_dump_t * mp) { - vl_api_registration_t *reg; snat_main_t *sm = &snat_main; - u32 *i; + vl_api_registration_t *reg; + snat_address_resolve_t *ap; reg = vl_api_client_index_to_registration (mp->client_index); if (!reg) return; - vec_foreach (i, sm->auto_add_sw_if_indices) + vec_foreach (ap, sm->addr_to_resolve) { - send_nat44_interface_addr_details (*i, reg, mp->context, 0); - } - vec_foreach (i, sm->auto_add_sw_if_indices_twice_nat) - { - send_nat44_interface_addr_details (*i, reg, mp->context, 1); + send_nat44_interface_addr_details (ap->sw_if_index, reg, mp->context, + ap->is_twice_nat); } } @@ -1321,253 +1162,160 @@ vl_api_nat44_forwarding_enable_disable_t_handler ( } static void -vl_api_nat44_forwarding_is_enabled_t_handler ( - vl_api_nat44_forwarding_is_enabled_t *mp) +vl_api_nat44_show_running_config_t_handler ( + vl_api_nat44_show_running_config_t *mp) { - vl_api_registration_t *reg; + vl_api_nat44_show_running_config_reply_t *rmp; snat_main_t *sm = &snat_main; - vl_api_nat44_forwarding_is_enabled_reply_t *rmp; - - reg = vl_api_client_index_to_registration (mp->client_index); - if (!reg) - return; + nat44_config_t *rc = &sm->rconfig; + int rv = 0; - rmp = vl_msg_api_alloc (sizeof (*rmp)); - clib_memset (rmp, 0, sizeof (*rmp)); - rmp->_vl_msg_id = - ntohs (VL_API_NAT44_FORWARDING_IS_ENABLED_REPLY + sm->msg_id_base); - rmp->context = mp->context; + REPLY_MACRO2_ZERO ( + VL_API_NAT44_SHOW_RUNNING_CONFIG_REPLY, ({ + rmp->inside_vrf = htonl (rc->inside_vrf); + rmp->outside_vrf = htonl (rc->outside_vrf); - rmp->enabled = sm->forwarding_enabled; + rmp->sessions = htonl (rc->sessions); + rmp->translation_buckets = htonl (sm->translation_buckets); - vl_api_send_msg (reg, (u8 *) rmp); -} + // OBSOLETE + rmp->users = 0; + rmp->user_buckets = 0; + rmp->user_sessions = 0; -/* Obsolete calls hold back because of deprecation - * should not be used */ + rmp->timeouts.udp = htonl (sm->timeouts.udp); + rmp->timeouts.tcp_established = htonl (sm->timeouts.tcp.established); + rmp->timeouts.tcp_transitory = htonl (sm->timeouts.tcp.transitory); + rmp->timeouts.icmp = htonl (sm->timeouts.icmp); -static void -vl_api_nat_set_addr_and_port_alloc_alg_t_handler ( - vl_api_nat_set_addr_and_port_alloc_alg_t *mp) -{ - snat_main_t *sm = &snat_main; - vl_api_nat_set_addr_and_port_alloc_alg_reply_t *rmp; - int rv = VNET_API_ERROR_UNSUPPORTED; - REPLY_MACRO (VL_API_NAT_SET_ADDR_AND_PORT_ALLOC_ALG_REPLY); + rmp->forwarding_enabled = sm->forwarding_enabled == 1; + // consider how to split functionality between subplugins + rmp->ipfix_logging_enabled = nat_ipfix_logging_enabled (); + rmp->flags |= NAT44_IS_ENDPOINT_DEPENDENT; + })); } static void -vl_api_nat_get_addr_and_port_alloc_alg_t_handler ( - vl_api_nat_get_addr_and_port_alloc_alg_t *mp) +vl_api_nat44_ed_add_del_vrf_table_t_handler ( + vl_api_nat44_ed_add_del_vrf_table_t *mp) { snat_main_t *sm = &snat_main; - vl_api_nat_get_addr_and_port_alloc_alg_reply_t *rmp; - int rv = VNET_API_ERROR_UNSUPPORTED; - REPLY_MACRO (VL_API_NAT_GET_ADDR_AND_PORT_ALLOC_ALG_REPLY); + vl_api_nat44_ed_add_del_vrf_table_reply_t *rmp; + int rv = nat44_ed_add_del_vrf_table (clib_net_to_host_u32 (mp->table_vrf_id), + mp->is_add); + REPLY_MACRO (VL_API_NAT44_ED_ADD_DEL_VRF_TABLE_REPLY); } static void -vl_api_nat_ha_set_listener_t_handler (vl_api_nat_ha_set_listener_t *mp) +vl_api_nat44_ed_add_del_vrf_route_t_handler ( + vl_api_nat44_ed_add_del_vrf_route_t *mp) { snat_main_t *sm = &snat_main; - vl_api_nat_ha_set_listener_reply_t *rmp; - int rv = VNET_API_ERROR_UNSUPPORTED; - REPLY_MACRO (VL_API_NAT_HA_SET_LISTENER_REPLY); + vl_api_nat44_ed_add_del_vrf_route_reply_t *rmp; + int rv = + nat44_ed_add_del_vrf_route (clib_net_to_host_u32 (mp->table_vrf_id), + clib_net_to_host_u32 (mp->vrf_id), mp->is_add); + REPLY_MACRO (VL_API_NAT44_ED_ADD_DEL_VRF_ROUTE_REPLY); } static void -vl_api_nat_ha_get_listener_t_handler (vl_api_nat_ha_get_listener_t *mp) +nat44_ed_vrf_tables_send_details (vl_api_registration_t *rp, u32 context, + vrf_table_t *t) { snat_main_t *sm = &snat_main; - vl_api_nat_ha_get_listener_reply_t *rmp; - int rv = VNET_API_ERROR_UNSUPPORTED; - REPLY_MACRO (VL_API_NAT_HA_GET_LISTENER_REPLY); -} + vl_api_nat44_ed_vrf_tables_details_t *mp; -static void -vl_api_nat_ha_set_failover_t_handler (vl_api_nat_ha_set_failover_t *mp) -{ - snat_main_t *sm = &snat_main; - vl_api_nat_ha_set_failover_reply_t *rmp; - int rv = VNET_API_ERROR_UNSUPPORTED; - REPLY_MACRO (VL_API_NAT_HA_SET_FAILOVER_REPLY); -} + u32 *vrf_ids = 0; + vrf_route_t *r; -static void -vl_api_nat_ha_get_failover_t_handler (vl_api_nat_ha_get_failover_t *mp) -{ - snat_main_t *sm = &snat_main; - vl_api_nat_ha_get_failover_reply_t *rmp; - int rv = VNET_API_ERROR_UNSUPPORTED; - REPLY_MACRO (VL_API_NAT_HA_GET_FAILOVER_REPLY); -} + mp = vl_msg_api_alloc_zero (sizeof (*mp) + + sizeof (mp->vrf_ids[0]) * vec_len (t->routes)); + mp->_vl_msg_id = + ntohs (VL_API_NAT44_ED_VRF_TABLES_DETAILS + sm->msg_id_base); + mp->context = context; + mp->n_vrf_ids = clib_host_to_net_u32 (vec_len (t->routes)); -static void -vl_api_nat_ha_flush_t_handler (vl_api_nat_ha_flush_t *mp) -{ - snat_main_t *sm = &snat_main; - vl_api_nat_ha_flush_reply_t *rmp; - int rv = VNET_API_ERROR_UNSUPPORTED; - REPLY_MACRO (VL_API_NAT_HA_FLUSH_REPLY); -} + pool_foreach (r, t->routes) + { + vec_add1 (vrf_ids, r->vrf_id); + } -static void -vl_api_nat_ha_resync_t_handler (vl_api_nat_ha_resync_t *mp) -{ - snat_main_t *sm = &snat_main; - vl_api_nat_ha_resync_reply_t *rmp; - int rv = VNET_API_ERROR_UNSUPPORTED; - REPLY_MACRO (VL_API_NAT_HA_RESYNC_REPLY); -} + // copy the records + clib_memcpy (mp->vrf_ids, vrf_ids, + sizeof (mp->vrf_ids[0]) * vec_len (t->routes)); -static void -vl_api_nat44_del_user_t_handler (vl_api_nat44_del_user_t *mp) -{ - snat_main_t *sm = &snat_main; - vl_api_nat44_del_user_reply_t *rmp; - int rv = VNET_API_ERROR_UNSUPPORTED; - REPLY_MACRO (VL_API_NAT44_DEL_USER_REPLY); -} + vec_free (vrf_ids); -static void -vl_api_nat44_session_cleanup_t_handler (vl_api_nat44_session_cleanup_t *mp) -{ - snat_main_t *sm = &snat_main; - vl_api_nat44_session_cleanup_reply_t *rmp; - int rv = VNET_API_ERROR_UNSUPPORTED; - REPLY_MACRO (VL_API_NAT44_SESSION_CLEANUP_REPLY); + // send the message + vl_api_send_msg (rp, (u8 *) mp); } static void -vl_api_nat44_plugin_enable_disable_t_handler ( - vl_api_nat44_plugin_enable_disable_t *mp) +nat44_ed_vrf_tables_send_details_v2 (vl_api_registration_t *rp, u32 context, + vrf_table_t *t) { snat_main_t *sm = &snat_main; - nat44_config_t c = { 0 }; - vl_api_nat44_plugin_enable_disable_reply_t *rmp; - int rv = 0; - - if (mp->enable) - { - if (mp->users || mp->user_sessions) - { - rv = VNET_API_ERROR_UNSUPPORTED; - } - else - { - c.static_mapping_only = mp->flags & NAT44_API_IS_STATIC_MAPPING_ONLY; - c.connection_tracking = mp->flags & NAT44_API_IS_CONNECTION_TRACKING; + vl_api_nat44_ed_vrf_tables_v2_details_t *mp; - c.inside_vrf = ntohl (mp->inside_vrf); - c.outside_vrf = ntohl (mp->outside_vrf); - - c.sessions = ntohl (mp->sessions); + u32 *vrf_ids = 0; + vrf_route_t *r; - rv = nat44_plugin_enable (c); - } - } - else + mp = vl_msg_api_alloc_zero (sizeof (*mp) + + sizeof (mp->vrf_ids[0]) * vec_len (t->routes)); + mp->_vl_msg_id = clib_net_to_host_u16 (VL_API_NAT44_ED_VRF_TABLES_DETAILS + + sm->msg_id_base); + mp->context = context; + mp->n_vrf_ids = clib_net_to_host_u32 (vec_len (t->routes)); + mp->table_vrf_id = clib_net_to_host_u32 (t->table_vrf_id); + pool_foreach (r, t->routes) { - rv = nat44_plugin_disable (); + vec_add1 (vrf_ids, clib_net_to_host_u32 (r->vrf_id)); } - REPLY_MACRO (VL_API_NAT44_PLUGIN_ENABLE_DISABLE_REPLY); -} + // copy the records + clib_memcpy (mp->vrf_ids, vrf_ids, + sizeof (mp->vrf_ids[0]) * vec_len (t->routes)); -static void -vl_api_nat_control_ping_t_handler (vl_api_nat_control_ping_t *mp) -{ - vl_api_nat_control_ping_reply_t *rmp; - snat_main_t *sm = &snat_main; - int rv = 0; + vec_free (vrf_ids); - REPLY_MACRO2 (VL_API_NAT_CONTROL_PING_REPLY, - ({ rmp->vpe_pid = ntohl (getpid ()); })); + // send the message + vl_api_send_msg (rp, (u8 *) mp); } static void -vl_api_nat_show_config_t_handler (vl_api_nat_show_config_t *mp) +vl_api_nat44_ed_vrf_tables_dump_t_handler ( + vl_api_nat44_ed_vrf_tables_dump_t *mp) { - vl_api_nat_show_config_reply_t *rmp; snat_main_t *sm = &snat_main; - int rv = 0; + vl_api_registration_t *rp; + vrf_table_t *t; - REPLY_MACRO2_ZERO (VL_API_NAT_SHOW_CONFIG_REPLY, ({ - rmp->translation_buckets = - htonl (sm->translation_buckets); - rmp->user_buckets = 0; - rmp->max_translations_per_user = 0; - rmp->outside_vrf_id = htonl (sm->outside_vrf_id); - rmp->inside_vrf_id = htonl (sm->inside_vrf_id); - rmp->static_mapping_only = sm->static_mapping_only; - rmp->static_mapping_connection_tracking = - sm->static_mapping_connection_tracking; - rmp->endpoint_dependent = 1; - rmp->out2in_dpo = 0; - })); -} - -static void -vl_api_nat_show_config_2_t_handler (vl_api_nat_show_config_2_t *mp) -{ - vl_api_nat_show_config_2_reply_t *rmp; - snat_main_t *sm = &snat_main; - int rv = 0; + rp = vl_api_client_index_to_registration (mp->client_index); + if (rp == 0) + return; - REPLY_MACRO2_ZERO ( - VL_API_NAT_SHOW_CONFIG_2_REPLY, ({ - rmp->translation_buckets = htonl (sm->translation_buckets); - rmp->user_buckets = 0; - rmp->max_translations_per_user = 0; - rmp->outside_vrf_id = htonl (sm->outside_vrf_id); - rmp->inside_vrf_id = htonl (sm->inside_vrf_id); - rmp->static_mapping_only = sm->static_mapping_only; - rmp->static_mapping_connection_tracking = - sm->static_mapping_connection_tracking; - rmp->endpoint_dependent = 1; - rmp->out2in_dpo = 0; - rmp->max_translations_per_thread = - clib_net_to_host_u32 (sm->max_translations_per_thread); - rmp->max_users_per_thread = 0; - })); + pool_foreach (t, sm->vrf_tables) + { + nat44_ed_vrf_tables_send_details (rp, mp->context, t); + } } static void -vl_api_nat44_show_running_config_t_handler ( - vl_api_nat44_show_running_config_t *mp) +vl_api_nat44_ed_vrf_tables_v2_dump_t_handler ( + vl_api_nat44_ed_vrf_tables_v2_dump_t *mp) { - vl_api_nat44_show_running_config_reply_t *rmp; snat_main_t *sm = &snat_main; - nat44_config_t *rc = &sm->rconfig; - int rv = 0; - - REPLY_MACRO2_ZERO ( - VL_API_NAT44_SHOW_RUNNING_CONFIG_REPLY, ({ - rmp->inside_vrf = htonl (rc->inside_vrf); - rmp->outside_vrf = htonl (rc->outside_vrf); - - rmp->sessions = htonl (rc->sessions); - rmp->translation_buckets = htonl (sm->translation_buckets); - - // OBSOLETE - rmp->users = 0; - rmp->user_buckets = 0; - rmp->user_sessions = 0; + vl_api_registration_t *rp; + vrf_table_t *t; - rmp->timeouts.udp = htonl (sm->timeouts.udp); - rmp->timeouts.tcp_established = htonl (sm->timeouts.tcp.established); - rmp->timeouts.tcp_transitory = htonl (sm->timeouts.tcp.transitory); - rmp->timeouts.icmp = htonl (sm->timeouts.icmp); + rp = vl_api_client_index_to_registration (mp->client_index); + if (rp == 0) + return; - rmp->forwarding_enabled = sm->forwarding_enabled == 1; - // consider how to split functionality between subplugins - rmp->ipfix_logging_enabled = nat_ipfix_logging_enabled (); - rmp->flags |= NAT44_IS_ENDPOINT_DEPENDENT; - if (rc->static_mapping_only) - rmp->flags |= NAT44_IS_STATIC_MAPPING_ONLY; - if (rc->connection_tracking) - rmp->flags |= NAT44_IS_CONNECTION_TRACKING; - })); + pool_foreach (t, sm->vrf_tables) + { + nat44_ed_vrf_tables_send_details_v2 (rp, mp->context, t); + } } /* user (internal host) key */ @@ -1797,7 +1545,8 @@ send_nat44_user_session_v2_details (snat_session_t *s, { vl_api_nat44_user_session_v2_details_t *rmp; snat_main_t *sm = &snat_main; - u64 now = vlib_time_now (sm->vnet_main->vlib_main); + vnet_main_t *vnm = vnet_get_main (); + u64 now = vlib_time_now (vnm->vlib_main); u64 sess_timeout_time = 0; rmp = vl_msg_api_alloc (sizeof (*rmp)); @@ -1830,26 +1579,54 @@ send_nat44_user_session_v2_details (snat_session_t *s, rmp->ext_host_nat_port = s->ext_host_nat_port; } - sess_timeout_time = s->last_heard; - switch (s->proto) + sess_timeout_time = s->last_heard + nat44_session_get_timeout (sm, s); + rmp->is_timed_out = (now >= sess_timeout_time); + + vl_api_send_msg (reg, (u8 *) rmp); +} + +static void +send_nat44_user_session_v3_details (snat_session_t *s, + vl_api_registration_t *reg, u32 context) +{ + vl_api_nat44_user_session_v3_details_t *rmp; + snat_main_t *sm = &snat_main; + u64 now = vlib_time_now (vlib_get_main ()); + u64 sess_timeout_time = 0; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + clib_memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = + ntohs (VL_API_NAT44_USER_SESSION_V3_DETAILS + sm->msg_id_base); + clib_memcpy (rmp->outside_ip_address, (&s->out2in.addr), 4); + clib_memcpy (rmp->inside_ip_address, (&s->in2out.addr), 4); + + if (nat44_ed_is_session_static (s)) + rmp->flags |= NAT_API_IS_STATIC; + + if (nat44_ed_is_twice_nat_session (s)) + rmp->flags |= NAT_API_IS_TWICE_NAT; + + rmp->flags |= NAT_API_IS_EXT_HOST_VALID; + + rmp->last_heard = clib_host_to_net_u64 ((u64) s->last_heard); + rmp->time_since_last_heard = + clib_host_to_net_u64 ((u64) (now - s->last_heard)); + rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes); + rmp->total_pkts = ntohl (s->total_pkts); + rmp->context = context; + rmp->outside_port = s->out2in.port; + rmp->inside_port = s->in2out.port; + rmp->protocol = clib_host_to_net_u16 (s->proto); + clib_memcpy (rmp->ext_host_address, &s->ext_host_addr, 4); + rmp->ext_host_port = s->ext_host_port; + if (nat44_ed_is_twice_nat_session (s)) { - case IP_PROTOCOL_TCP: - if (s->state) - sess_timeout_time += sm->timeouts.tcp.established; - else - sess_timeout_time += sm->timeouts.tcp.transitory; - break; - case IP_PROTOCOL_UDP: - sess_timeout_time += sm->timeouts.udp; - break; - case IP_PROTOCOL_ICMP: - sess_timeout_time += sm->timeouts.icmp; - break; - default: - sess_timeout_time += sm->timeouts.udp; - break; + clib_memcpy (rmp->ext_host_nat_address, &s->ext_host_nat_addr, 4); + rmp->ext_host_nat_port = s->ext_host_nat_port; } + sess_timeout_time = s->last_heard + nat44_session_get_timeout (sm, s); rmp->is_timed_out = (now >= sess_timeout_time); vl_api_send_msg (reg, (u8 *) rmp); @@ -1889,6 +1666,40 @@ vl_api_nat44_user_session_v2_dump_t_handler ( } } +static void +vl_api_nat44_user_session_v3_dump_t_handler ( + vl_api_nat44_user_session_v3_dump_t *mp) +{ + snat_main_per_thread_data_t *tsm; + snat_main_t *sm = &snat_main; + vl_api_registration_t *reg; + snat_user_key_t ukey; + snat_session_t *s; + ip4_header_t ip; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + clib_memcpy (&ukey.addr, mp->ip_address, 4); + ip.src_address.as_u32 = ukey.addr.as_u32; + ukey.fib_index = fib_table_find (FIB_PROTOCOL_IP4, ntohl (mp->vrf_id)); + if (sm->num_workers > 1) + tsm = vec_elt_at_index ( + sm->per_thread_data, + nat44_ed_get_in2out_worker_index (0, &ip, ukey.fib_index, 0)); + else + tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); + + pool_foreach (s, tsm->sessions) + { + if (s->in2out.addr.as_u32 == ukey.addr.as_u32) + { + send_nat44_user_session_v3_details (s, reg, mp->context); + } + } +} + /* API definitions */ #include <vnet/format_fns.h> #include <nat/nat44-ed/nat44_ed.api.c> diff --git a/src/plugins/nat/nat44-ed/nat44_ed_cfg.c b/src/plugins/nat/nat44-ed/nat44_ed_cfg.c deleted file mode 100644 index e69de29bb2d..00000000000 --- a/src/plugins/nat/nat44-ed/nat44_ed_cfg.c +++ /dev/null diff --git a/src/plugins/nat/nat44-ed/nat44_ed_cli.c b/src/plugins/nat/nat44-ed/nat44_ed_cli.c index ba74b7dd51f..14313d05a35 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_cli.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_cli.c @@ -38,23 +38,15 @@ nat44_ed_enable_disable_command_fn (vlib_main_t *vm, unformat_input_t *input, clib_error_t *error = 0; nat44_config_t c = { 0 }; - u8 enable_set = 0, enable = 0, mode_set = 0; + u8 enable_set = 0, enable = 0; if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - if (!mode_set && unformat (line_input, "static-mapping-only")) - { - mode_set = 1; - c.static_mapping_only = 1; - if (unformat (line_input, "connection-tracking")) - { - c.connection_tracking = 1; - } - } - else if (unformat (line_input, "inside-vrf %u", &c.inside_vrf)); + if (unformat (line_input, "inside-vrf %u", &c.inside_vrf)) + ; else if (unformat (line_input, "outside-vrf %u", &c.outside_vrf)); else if (unformat (line_input, "sessions %u", &c.sessions)); else if (!enable_set) @@ -116,7 +108,6 @@ set_workers_command_fn (vlib_main_t * vm, int rv = 0; clib_error_t *error = 0; - /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); @@ -189,10 +180,9 @@ snat_set_log_level_command_fn (vlib_main_t * vm, { unformat_input_t _line_input, *line_input = &_line_input; snat_main_t *sm = &snat_main; - u8 log_level = NAT_LOG_NONE; + u32 log_level = NAT_LOG_NONE; clib_error_t *error = 0; - /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); @@ -307,7 +297,6 @@ nat_set_mss_clamping_command_fn (vlib_main_t * vm, unformat_input_t * input, clib_error_t *error = 0; u32 mss; - /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); @@ -350,7 +339,6 @@ add_address_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; - snat_main_t *sm = &snat_main; ip4_address_t start_addr, end_addr, this_addr; u32 start_host_order, end_host_order; u32 vrf_id = ~0; @@ -360,7 +348,6 @@ add_address_command_fn (vlib_main_t * vm, clib_error_t *error = 0; u8 twice_nat = 0; - /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); @@ -386,12 +373,6 @@ add_address_command_fn (vlib_main_t * vm, } } - if (sm->static_mapping_only) - { - error = clib_error_return (0, "static mapping only mode"); - goto done; - } - start_host_order = clib_host_to_net_u32 (start_addr.as_u32); end_host_order = clib_host_to_net_u32 (end_addr.as_u32); @@ -418,7 +399,7 @@ add_address_command_fn (vlib_main_t * vm, } else { - rv = nat44_ed_del_address (this_addr, 0, twice_nat); + rv = nat44_ed_del_address (this_addr, twice_nat); } switch (rv) @@ -493,16 +474,12 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, u64 now = vlib_time_now (vm); u64 sess_timeout_time = 0; - u32 udp_sessions = 0; - u32 tcp_sessions = 0; - u32 icmp_sessions = 0; - u32 other_sessions = 0; - - u32 timed_out = 0; - u32 transitory = 0; - u32 transitory_wait_closed = 0; - u32 transitory_closed = 0; - u32 established = 0; + struct + { + u32 total; + u32 timed_out; + } udp = { 0 }, tcp = { 0 }, tcp_established = { 0 }, tcp_transitory = { 0 }, + icmp = { 0 }, other = { 0 }; u32 fib; @@ -516,43 +493,44 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, { pool_foreach (s, tsm->sessions) { - sess_timeout_time = s->last_heard + - (f64) nat44_session_get_timeout (sm, s); - if (now >= sess_timeout_time) - timed_out++; - - switch (s->proto) - { - case IP_PROTOCOL_ICMP: - icmp_sessions++; - break; - case IP_PROTOCOL_TCP: - tcp_sessions++; - if (s->state) - { - if (s->tcp_closed_timestamp) - { - if (now >= s->tcp_closed_timestamp) - { - ++transitory_closed; - } - else - { - ++transitory_wait_closed; - } - } - transitory++; - } - else - established++; - break; - case IP_PROTOCOL_UDP: - udp_sessions++; - break; - default: - ++other_sessions; - break; - } + sess_timeout_time = + s->last_heard + (f64) nat44_session_get_timeout (sm, s); + + switch (s->proto) + { + case IP_PROTOCOL_ICMP: + ++icmp.total; + if (now >= sess_timeout_time) + ++icmp.timed_out; + break; + case IP_PROTOCOL_TCP: + ++tcp.total; + if (now >= sess_timeout_time) + ++tcp.timed_out; + if (nat44_ed_tcp_is_established (s->tcp_state)) + { + ++tcp_established.total; + if (now >= sess_timeout_time) + ++tcp_established.timed_out; + } + else + { + ++tcp_transitory.total; + if (now >= sess_timeout_time) + ++tcp_transitory.timed_out; + } + break; + case IP_PROTOCOL_UDP: + ++udp.total; + if (now >= sess_timeout_time) + ++udp.timed_out; + break; + default: + ++other.total; + if (now >= sess_timeout_time) + ++other.timed_out; + break; + } } nat44_show_lru_summary (vm, tsm, now, sess_timeout_time); count += pool_elts (tsm->sessions); @@ -565,39 +543,40 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, { sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s); - if (now >= sess_timeout_time) - timed_out++; switch (s->proto) { case IP_PROTOCOL_ICMP: - icmp_sessions++; + ++icmp.total; + if (now >= sess_timeout_time) + ++icmp.timed_out; break; case IP_PROTOCOL_TCP: - tcp_sessions++; - if (s->state) + ++tcp.total; + if (now >= sess_timeout_time) + ++tcp.timed_out; + if (nat44_ed_tcp_is_established (s->tcp_state)) { - if (s->tcp_closed_timestamp) - { - if (now >= s->tcp_closed_timestamp) - { - ++transitory_closed; - } - else - { - ++transitory_wait_closed; - } - } - transitory++; + ++tcp_established.total; + if (now >= sess_timeout_time) + ++tcp_established.timed_out; } else - established++; + { + ++tcp_transitory.total; + if (now >= sess_timeout_time) + ++tcp_transitory.timed_out; + } break; case IP_PROTOCOL_UDP: - udp_sessions++; + ++udp.total; + if (now >= sess_timeout_time) + ++udp.timed_out; break; default: - ++other_sessions; + ++other.total; + if (now >= sess_timeout_time) + ++other.timed_out; break; } } @@ -605,18 +584,25 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, count = pool_elts (tsm->sessions); } - vlib_cli_output (vm, "total timed out sessions: %u", timed_out); - vlib_cli_output (vm, "total sessions: %u", count); - vlib_cli_output (vm, "total tcp sessions: %u", tcp_sessions); - vlib_cli_output (vm, "total tcp established sessions: %u", established); - vlib_cli_output (vm, "total tcp transitory sessions: %u", transitory); - vlib_cli_output (vm, "total tcp transitory (WAIT-CLOSED) sessions: %u", - transitory_wait_closed); - vlib_cli_output (vm, "total tcp transitory (CLOSED) sessions: %u", - transitory_closed); - vlib_cli_output (vm, "total udp sessions: %u", udp_sessions); - vlib_cli_output (vm, "total icmp sessions: %u", icmp_sessions); - vlib_cli_output (vm, "total other sessions: %u", other_sessions); + u32 timed_out = + tcp.timed_out + icmp.timed_out + udp.timed_out + other.timed_out; + vlib_cli_output (vm, "total sessions: %u (timed out: %u)", count, timed_out); + vlib_cli_output (vm, "tcp sessions:"); + vlib_cli_output (vm, " total: %u (timed out: %u)", tcp.total, + tcp.timed_out); + vlib_cli_output (vm, " established: %u (timed out: %u)", + tcp_established.total, tcp_established.timed_out); + vlib_cli_output (vm, " transitory: %u (timed out: %u)", + tcp_transitory.total, tcp_transitory.timed_out); + vlib_cli_output (vm, "udp sessions:"); + vlib_cli_output (vm, " total: %u (timed out: %u)", udp.total, + udp.timed_out); + vlib_cli_output (vm, "icmp sessions:"); + vlib_cli_output (vm, " total: %u (timed out: %u)", icmp.total, + icmp.timed_out); + vlib_cli_output (vm, "other sessions:"); + vlib_cli_output (vm, " total: %u (timed out: %u)", other.total, + other.timed_out); return 0; } @@ -632,10 +618,14 @@ nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input, { vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr); if (ap->fib_index != ~0) - vlib_cli_output (vm, " tenant VRF: %u", - fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id); + vlib_cli_output ( + vm, " tenant VRF: %u", + fib_table_get (ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id); else vlib_cli_output (vm, " tenant VRF independent"); + + if (ap->addr_len != ~0) + vlib_cli_output (vm, " synced with interface address"); } vlib_cli_output (vm, "NAT44 twice-nat pool addresses:"); vec_foreach (ap, sm->twice_nat_addresses) @@ -646,6 +636,9 @@ nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input, fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id); else vlib_cli_output (vm, " tenant VRF independent"); + + if (ap->addr_len != ~0) + vlib_cli_output (vm, " synced with interface address"); } return 0; } @@ -665,7 +658,6 @@ snat_feature_command_fn (vlib_main_t * vm, sw_if_index = ~0; - /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); @@ -919,8 +911,6 @@ add_static_mapping_command_fn (vlib_main_t * vm, e_port = clib_host_to_net_u16 (e_port); } - // TODO: specific pool_addr for both pool & twice nat pool ? - if (is_add) { rv = @@ -933,25 +923,17 @@ add_static_mapping_command_fn (vlib_main_t * vm, vrf_id, sw_if_index, flags); } - // TODO: fix returns - switch (rv) { - case VNET_API_ERROR_INVALID_VALUE: - error = clib_error_return (0, "External port already in use."); - goto done; + case VNET_API_ERROR_UNSUPPORTED: + error = clib_error_return (0, "Plugin disabled."); + break; case VNET_API_ERROR_NO_SUCH_ENTRY: - if (is_add) - error = clib_error_return (0, "External address must be allocated."); - else - error = clib_error_return (0, "Mapping not exist."); - goto done; - case VNET_API_ERROR_NO_SUCH_FIB: - error = clib_error_return (0, "No such VRF id."); - goto done; + error = clib_error_return (0, "Mapping not exist."); + break; case VNET_API_ERROR_VALUE_EXIST: error = clib_error_return (0, "Mapping already exist."); - goto done; + break; default: break; } @@ -962,7 +944,6 @@ done: return error; } -// TODO: either delete this bullshit or update it static clib_error_t * add_identity_mapping_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -979,7 +960,6 @@ add_identity_mapping_command_fn (vlib_main_t * vm, flags = NAT_SM_FLAG_IDENTITY_NAT; - /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); @@ -1032,25 +1012,17 @@ add_identity_mapping_command_fn (vlib_main_t * vm, sw_if_index, flags); } - // TODO: fix returns - switch (rv) { - case VNET_API_ERROR_INVALID_VALUE: - error = clib_error_return (0, "External port already in use."); - goto done; + case VNET_API_ERROR_UNSUPPORTED: + error = clib_error_return (0, "Plugin disabled."); + break; case VNET_API_ERROR_NO_SUCH_ENTRY: - if (is_add) - error = clib_error_return (0, "External address must be allocated."); - else - error = clib_error_return (0, "Mapping not exist."); - goto done; - case VNET_API_ERROR_NO_SUCH_FIB: - error = clib_error_return (0, "No such VRF id."); - goto done; + error = clib_error_return (0, "Mapping not exist."); + break; case VNET_API_ERROR_VALUE_EXIST: error = clib_error_return (0, "Mapping already exist."); - goto done; + break; default: break; } @@ -1076,7 +1048,6 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm, int rv, is_add = 1; u32 flags = 0; - /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); @@ -1087,6 +1058,7 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm, { clib_memset (&local, 0, sizeof (local)); local.addr = l_addr; + l_port = clib_host_to_net_u16 (l_port); local.port = (u16) l_port; local.probability = (u8) probability; vec_add1 (locals, local); @@ -1097,6 +1069,7 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm, { clib_memset (&local, 0, sizeof (local)); local.addr = l_addr; + l_port = clib_host_to_net_u16 (l_port); local.port = (u16) l_port; local.probability = (u8) probability; local.vrf_id = vrf_id; @@ -1104,7 +1077,9 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm, } else if (unformat (line_input, "external %U:%u", unformat_ip4_address, &e_addr, &e_port)) - ; + { + e_port = clib_host_to_net_u16 (e_port); + } else if (unformat (line_input, "protocol %U", unformat_ip_protocol, &proto)) { @@ -1196,7 +1171,6 @@ add_lb_backend_command_fn (vlib_main_t * vm, ip_protocol_t proto; u8 proto_set = 0; - /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); @@ -1272,14 +1246,14 @@ nat44_show_static_mappings_command_fn (vlib_main_t * vm, { snat_main_t *sm = &snat_main; snat_static_mapping_t *m; - snat_static_map_resolve_t *rp; + snat_static_mapping_resolve_t *rp; vlib_cli_output (vm, "NAT44 static mappings:"); pool_foreach (m, sm->static_mappings) { vlib_cli_output (vm, " %U", format_snat_static_mapping, m); } - vec_foreach (rp, sm->to_resolve) + vec_foreach (rp, sm->sm_to_resolve) vlib_cli_output (vm, " %U", format_snat_static_map_to_resolve, rp); return 0; @@ -1291,19 +1265,21 @@ snat_add_interface_address_command_fn (vlib_main_t * vm, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; - snat_main_t *sm = &snat_main; + vnet_main_t *vnm = vnet_get_main (); clib_error_t *error = 0; int rv, is_del = 0; u8 twice_nat = 0; u32 sw_if_index; + sw_if_index = ~0; + if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - if (unformat (line_input, "%U", unformat_vnet_sw_interface, - sm->vnet_main, &sw_if_index)) + if (unformat (line_input, "%U", unformat_vnet_sw_interface, vnm, + &sw_if_index)) ; else if (unformat (line_input, "twice-nat")) { @@ -1321,23 +1297,151 @@ snat_add_interface_address_command_fn (vlib_main_t * vm, } } - if (!is_del) + if (is_del) + { + rv = nat44_ed_del_interface_address (sw_if_index, twice_nat); + } + else { rv = nat44_ed_add_interface_address (sw_if_index, twice_nat); - if (rv) + } + + if (0 != rv) + { + error = + clib_error_return (0, "%s %U address failed", is_del ? "del" : "add", + format_vnet_sw_if_index_name, vnm, sw_if_index); + goto done; + } + +done: + unformat_free (line_input); + + return error; +} + +static clib_error_t * +nat44_ed_add_del_vrf_table_command_fn (vlib_main_t *vm, + unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = 0; + bool is_add = true, not_set = true; + u32 vrf_id = ~0; + int rv; + + if (!unformat_user (input, unformat_line_input, line_input)) + return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%u", &vrf_id)) + ; + else if (not_set) + { + if (unformat (line_input, "add")) + { + is_add = true; + } + else if (unformat (line_input, "del")) + { + is_add = false; + } + not_set = false; + } + else { - error = clib_error_return (0, "add address returned %d", rv); + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; } } - else + + if (not_set) { - rv = nat44_ed_del_interface_address (sw_if_index, twice_nat); - if (rv) + error = clib_error_return (0, "missing required parameter"); + goto done; + } + + if (~0 == vrf_id) + { + error = clib_error_return (0, "missing vrf id"); + goto done; + } + + rv = nat44_ed_add_del_vrf_table (vrf_id, is_add); + if (rv) + { + error = clib_error_return (0, "%s vrf table returned %d", + is_add ? "add" : "del", rv); + } + +done: + unformat_free (line_input); + + return error; +} + +static clib_error_t * +nat44_ed_add_del_vrf_route_command_fn (vlib_main_t *vm, + unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = 0; + bool is_add = true, not_set = true; + u32 vrf_id = ~0, table_vrf_id = ~0; + int rv; + + if (!unformat_user (input, unformat_line_input, line_input)) + return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "table %u", &table_vrf_id)) + ; + else if (unformat (line_input, "%u", &vrf_id)) + ; + else if (not_set) { - error = clib_error_return (0, "del address returned %d", rv); + if (unformat (line_input, "add")) + { + is_add = true; + } + else if (unformat (line_input, "del")) + { + is_add = false; + } + not_set = false; + } + else + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; } } + if (not_set) + { + error = clib_error_return (0, "missing required parameter"); + goto done; + } + + if ((~0 == vrf_id) || (~0 == table_vrf_id)) + { + error = clib_error_return (0, "missing vrf id"); + goto done; + } + + rv = nat44_ed_add_del_vrf_route (table_vrf_id, vrf_id, is_add); + if (rv) + { + error = clib_error_return (0, "%s vrf table returned %d", + is_add ? "add" : "del", rv); + } + done: unformat_free (line_input); @@ -1345,27 +1449,42 @@ done: } static clib_error_t * +nat44_ed_show_vrf_tables_command_fn (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + snat_main_t *sm = &snat_main; + vrf_table_t *t; + vrf_route_t *r; + int i = 0; + + pool_foreach (t, sm->vrf_tables) + { + vlib_cli_output (vm, "table %u:", t->table_vrf_id); + pool_foreach (r, t->routes) + { + vlib_cli_output (vm, "[%u] vrf-id %u", i, r->vrf_id); + i++; + } + } + + return 0; +} + +static clib_error_t * nat44_show_interface_address_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { snat_main_t *sm = &snat_main; vnet_main_t *vnm = vnet_get_main (); - u32 *sw_if_index; + snat_address_resolve_t *ap; vlib_cli_output (vm, "NAT44 pool address interfaces:"); - vec_foreach (sw_if_index, sm->auto_add_sw_if_indices) - { - vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm, - *sw_if_index); - } - vlib_cli_output (vm, "NAT44 twice-nat pool address interfaces:"); - vec_foreach (sw_if_index, sm->auto_add_sw_if_indices_twice_nat) + vec_foreach (ap, sm->addr_to_resolve) { - vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm, - *sw_if_index); + vlib_cli_output (vm, " %U%s", format_vnet_sw_if_index_name, vnm, + ap->sw_if_index, ap->is_twice_nat ? " twice-nat" : ""); } - return 0; } @@ -1471,7 +1590,8 @@ print: continue; showed_sessions++; } - vlib_cli_output (vm, " %U\n", format_snat_session, tsm, s); + vlib_cli_output (vm, " %U\n", format_snat_session, sm, tsm, s, + vlib_time_now (vm)); } if (filtering) { @@ -1727,21 +1847,19 @@ done: * @cliexstart{nat44} * Enable nat44 plugin * To enable nat44-ed, use: - * vpp# nat44 enable + * vpp# nat44 plugin enable * To disable nat44-ed, use: - * vpp# nat44 disable - * To enable nat44-ed static mapping with connection tracking, use: - * vpp# nat44-ed enable static-mapping connection-tracking + * vpp# nat44 plugin disable * To set inside-vrf outside-vrf, use: - * vpp# nat44 enable inside-vrf <id> outside-vrf <id> + * vpp# nat44 plugin enable inside-vrf <id> outside-vrf <id> * @cliexend ?*/ VLIB_CLI_COMMAND (nat44_ed_enable_disable_command, static) = { - .path = "nat44", - .short_help = "nat44 <enable [sessions <max-number>] [static-mapping-only " - "connection-tracking] [inside-vrf <vrf-id>] " - "[outside-vrf <vrf-id>]>|disable", + .path = "nat44 plugin", .function = nat44_ed_enable_disable_command_fn, + .short_help = + "nat44 plugin <enable [sessions <max-number>] [inside-vrf <vrf-id>] " + "[outside-vrf <vrf-id>]>|disable", }; /*? @@ -2098,9 +2216,48 @@ VLIB_CLI_COMMAND (nat44_show_static_mappings_command, static) = { * @cliexend ?*/ VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = { - .path = "nat44 add interface address", - .short_help = "nat44 add interface address <interface> [twice-nat] [del]", - .function = snat_add_interface_address_command_fn, + .path = "nat44 add interface address", + .function = snat_add_interface_address_command_fn, + .short_help = "nat44 add interface address <interface> [twice-nat] [del]", +}; + +/*? + * @cliexpar + * @cliexstart{nat44 vrf table} + * Add empty inter VRF routing table + * vpp# nat44 vrf table add 10 + * @cliexend +?*/ +VLIB_CLI_COMMAND (nat44_ed_add_del_vrf_table_command, static) = { + .path = "nat44 vrf table", + .short_help = "nat44 vrf table [add|del] <vrf-id>", + .function = nat44_ed_add_del_vrf_table_command_fn, +}; + +/*? + * @cliexpar + * @cliexstart{nat44 vrf route} + * Add inter VRF route record to VRF routing table + * vpp# nat44 vrf route add table 10 20 + * @cliexend +?*/ +VLIB_CLI_COMMAND (nat44_ed_add_del_vrf_route_command, static) = { + .path = "nat44 vrf route", + .short_help = "nat44 vrf route [add|del] table <vrf-id> <vrf-id>", + .function = nat44_ed_add_del_vrf_route_command_fn, +}; + +/*? + * @cliexpar + * @cliexstart{show nat44 vrf tables} + * Show inter VRF route tables + * vpp# show nat44 vrf tables + * @cliexend +?*/ +VLIB_CLI_COMMAND (nat44_ed_show_vrf_tables_command, static) = { + .path = "show nat44 vrf tables", + .short_help = "show nat44 vrf tables", + .function = nat44_ed_show_vrf_tables_command_fn, }; /*? diff --git a/src/plugins/nat/nat44-ed/nat44_ed_doc.rst b/src/plugins/nat/nat44-ed/nat44_ed_doc.rst new file mode 100644 index 00000000000..a6c461d4260 --- /dev/null +++ b/src/plugins/nat/nat44-ed/nat44_ed_doc.rst @@ -0,0 +1,729 @@ +.. _NAT44_Endpoint_Dependent: + +.. toctree:: + +NAT44-ED: NAT44 Endpoint Dependent +================================== + +Introduction +------------ + +NAT44-ED is the IPv4 endpoint dependent network address translation +plugin. The component implements an address and port-dependent mapping +and address and port-dependent filtering NAT as described in +`RFC4787 <https://tools.ietf.org/html/rfc4787>`__. + +The outside address and port (X1’:x1’) is reused for internal hosts +(X:x) for different values of Y:y. A flow is matched by {source address, +destination address, protocol, transport source port, transport +destination port, fib index}. As long as all these are unique the +mapping is valid. While a single outside address in theory allows for +2^16 source ports \* 2^32 destination IP addresses \* 2^16 destination +ports = 2^64 sessions, this number is much smaller in practice. Few +destination ports are generally used (80, 443) and a fraction of the IP +address space is available. The limitation is 2^16 bindings per outside +IP address to a single destination address and port (Y:y). + +The implementation is split, a control-plane / slow-path and a +data-plane / fast-path. Essentially acting as a flow router. The +data-plane does a 6-tuple flow lookup (SA, DA, P, SP, DP, FIB) and on a +match runs the per-flow packet handling instructions on the packet. On a +flow lookup miss, the packet is punted to the slow-path, where depending +on policy new sessions are created. + +The support set of packet handling instructions is ever-increasing. +Currently, the implementation supports rewrite of SA, DA, SP, DP and TCP +MSS. The fast-path also does connection tracking and expiry of older +sessions. + +NAT44-ED uses 6 +tuple\ ``(src address, src port, dst address, dst port, protocol and fib)``\ for +matching communication. + +Structure +~~~~~~~~~ + +1) Dynamic NAT + +- also called PAT (Port Address Translation) +- supports port overloading + +2) Static NAT + +- types of Static NAT: + + a) identity mapping + + - exceptions to translations + + b) static mapping + + - supported features: + + 1. address only mapping + + - one to one translation without ports + + 2. twice-nat + + - double-nat, translation of source and destination + + 3. self-twice-nat + + - double nat, translation of source and destination, where + external host address is the same as local host address + + 4. out2in-only mapping + + - session is created only from outside interface (out2in feature) + + c) load balanced static mapping + + - translates one frontend (``addr``:``port``) to multiple backends + (``addr``:``port``) + +3) Interfaces + +a) inside interface (in2out feature) - local to external network + translation - feature is before ip4-lookup +b) outside interface (out2in feature) - external to local network + translation - feature is before ip4-lookup +c) inside & outside interface (classify feature) - local or external + network translation - correct type of translation is determined per + communication - feature is before ip4-lookup +d) output interface (output feature) - used for post routing translation + - feature is after ip4-lookup + +4) Addresses + +a) interface address - automatically managed external address - first + address of VPP interface +b) pool address - range of external addresses + +5) Logging and Accounting + +a) ipfix logging +b) syslog + +6) Miscellaneous Features + +a) inter-vrf translation control 1. basic + + - nat44 plugin enable inside-vrf / outside-vrf + - inside/outside interface vrf’s + + 2. advanced + + - vrf table routing feature + +b) udp/tcp/icmp timeouts - configurable timeouts for these protocols +c) session limiting 1. basic (plugin enable [sessions ] 2. advanced + (per vrf table / global limiting) +d) mss-clamping - MSS (maximum segment size) is by default determined by + egress interface MTU (maximum transmission unit) size - used to lower + MSS value in VPN tunnel scenarios where additional headers can + enlarge the packet beyond MTU causing drops +e) hairpinning - hosts on the same lan segment communicating via + external address +f) forwarding - if enabled translation only occurs if active session or + static configuration exist, rest of the traffic is passed without + being translated + +Session Table +------------- + +Session table exists per thread and contains pool of sessions that can +be either expired or not expired. NAT44-ED plugin doesn’t use scavenging +for clearing expired sessions. Rather then using scavenging plugin uses +LRU doubly-linked list. LRU contains ordered list of sessions indices. +Head of the list contains last updated session. Each session holds +record of the LRU head (tcp transitory, tcp established, udp, icmp or +unknown lru head). Because of this plugin can reach maximum number of +sessions without requirement to clear old sessions. During session +creation if a maximum number of sessions was reached LRU head is +checked. Expired head record gets deleted and a new session gets +created. For better performance LRU head records exist. Each time a new +packet is received session index gets moved to the tail of LRU list. + +Terminology +----------- + +IN2OUT (inside to outside translation) OUT2IN (outside to inside +translation) + +NAT (network address translation) PAT (port address translation) MSS +(maximum segment size) MTU (maximum transmission unit) VRF (virtual +routing and forwarding) + +HAIRPINNING + +Dynamic NAT (Minimal Required Configuration) +-------------------------------------------- + +:: + + +-------------+ + | 10.0.0.0/24 | + +-------------+ + | + +----------------------+ + | GigabitEthernet0/8/0 | + +----------------------+ + +----------------------+ + | GigabitEthernet0/a/0 | + +----------------------+ + | + +-------------+ + | 10.0.1.0/24 | + +-------------+ + +1) enable nat plugin + +.. + + nat44 plugin enable sessions 10000 + +2) configure NAT interfaces, two options: + +a) add inside NAT interface on local VPP interface, add outside NAT + interface on external VPP interface + +.. + + set interface nat44 in GigabitEthernet0/8/0 out GigabitEthernet0/a/0 + +b) add output NAT interface on external VPP interface + +.. + + set interface nat44 in GigabitEthernet0/a/0 output-feature + +3) configure NAT address + +a) add external address range + +.. + + nat44 add address 10.0.1.1 + +b) add external VPP interface address + +.. + + nat44 add interface address GigabitEthernet0/a/0 + +Static NAT +---------- + +Identity Mapping +~~~~~~~~~~~~~~~~ + + nat44 add identity mapping ``ip4-addr``\ \|external ``interface`` + [``protocol`` ``port``] [vrf ``table-id``] [del] + +Static Mapping +~~~~~~~~~~~~~~ + + nat44 add static mapping tcp|udp|icmp local ``addr`` + [``port|icmp-echo-id``] external ``addr`` [``port|icmp-echo-id``] + [vrf ``table-id``] [twice-nat|self-twice-nat] [out2in-only] [exact + ``pool-addr``] [del] + +Load Balanced Static Mapping +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + nat44 add load-balancing back-end protocol tcp|udp external + ``addr``:``port`` local ``addr``:``port`` [vrf ``table-id``] + probability ``n`` [del] + +.. + + nat44 add load-balancing static mapping protocol tcp|udp external + ``addr``:``port`` local ``addr``:``port`` [vrf ``table-id``] + probability ``n`` [twice-nat|self-twice-nat] [out2in-only] [affinity + ``timeout-seconds``] [del] + +Interfaces +---------- + +Inside Interface +~~~~~~~~~~~~~~~~ + +:: + + NAT INSIDE IF + +----------------------+ + | GigabitEthernet0/8/0 | + +----------------------+ + +.. + + set interface nat44 in GigabitEthernet0/8/0 [del] + +NAT inside interface is used for translating local to external +communication. Translates Dynamic and Static NAT traffic. If no matching +session is found a new session is created for both Dynamic NAT and +Static NAT. Dynamic NAT sessions can get created only on inside +interface. + +Outside Interface +~~~~~~~~~~~~~~~~~ + +:: + + NAT OUTSIDE IF + +----------------------+ + | GigabitEthernet0/a/0 | + +----------------------+ + +.. + + set interface nat44 out GigabitEthernet0/a/0 [del] + +NAT outside interface is used for translating external to local +communication. Translates Dynamic and Static NAT traffic. New session +gets created only if no matching session is found and matching Static +NAT configuration exists. + +Inside & Outside Interface +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + NAT IN AND OUT IF + +----------------------+ + | GigabitEthernet0/8/0 | + +----------------------+ + NAT IN AND OUT IF + +----------------------+ + | GigabitEthernet0/a/0 | + +----------------------+ + +.. + + set interface nat44 in GigabitEthernet0/8/0 out GigabitEthernet0/8/0 + [del] + + set interface nat44 in GigabitEthernet0/a/0 out GigabitEthernet0/a/0 + [del] + +If one VPP interface is configured both as inside and outside NAT +interface then classification feature is used. By default NAT inside +interface uses in2out feature and NAT outside uses out2in feature. +Classification feature determines if the communication should be passed +to in2out feature or to out2in feature. Traffic will get passed to +out2in feature if destination address is one of NAT addresses or a +static mapping in out2in direction flow matches this communication. By +default all traffic is passed to in2out feature. + +Output Interface +~~~~~~~~~~~~~~~~ + +:: + + +-------------+ +-------------+ + | 10.0.2.0/24 | | 10.0.3.0/24 | + +-------------+ +-------------+ + | | + +----------------------+ +----------------------+ + | GigabitEthernet0/7/0 | | GigabitEthernet0/8/0 | + +----------------------+ +----------------------+ + NAT OUTPUT IF + +----------------------+ + | GigabitEthernet0/a/0 | + +----------------------+ + +----------+ + | 10.0.1.1 | + +----------+ + | + +-------------+ + | 10.0.1.0/24 | + +-------------+ + +.. + + set interface nat44 in GigabitEthernet0/a/0 output-feature [del] + +NAT output interface acts as both inside and outside interfaces. Inside +rules apply for all egress communication on VPP interface and outside +rules apply for all ingress communication. Compared to inside/outside +NAT configuration method non of the local interfaces require to be +configured as inside NAT interfaces. Translation only occurs after +routing decision has been made and just before leaving NAT output +interface. In above example all traffic destined for 10.0.1.0/24 from +10.0.2.0/24 or 10.0.3.0/24 will get translated. NAT output interface +acts as post-routing feature. + +Addresses +--------- + +Interface Address +~~~~~~~~~~~~~~~~~ + + nat44 add interface address ``interface`` `twice-nat <#twice-nat>`__ + [del] + +NAT interface address is a standard external pool address that gets auto +added upon resolving first VPP interface address. Supports both standard +address and twice-nat address. Twice-nat address is used in conjunction +with static mapping twice-nat and self-twice-nat feature. + +Pool Address +~~~~~~~~~~~~ + + nat44 add address ``ip4-range-start`` [- ``ip4-range-end``] + [tenant-vrf ``vrf-id``] `twice-nat <#twice-nat>`__ [del] + +Statically configured address or range of addresses that supports both +standard and twice-nat address. Specifying vrf-id lets user assign +address/addresses to specific NAT inside interfaces that belong to the +same vrf table. + +Logging +------- + + nat set logging level ``level`` + +Configuration of logging level is used only for internal VPP logging. + + nat ipfix logging [domain ``domain-id``] [src-port ``port``] + [disable] + +Both syslog and ipfix support connection tracking capabilities. Session +creation, session deletion, maximum sessions exceeded among other things +are logged by syslog and ipfix. + +Miscellaneous +------------- + +VRFs +~~~~ + +:: + + VRF 0 VRF 1 + +-------------+ +-------------+ + | 10.0.2.0/24 | | 10.0.3.0/24 | + +-------------+ +-------------+ + | | + NAT INSIDE IF NAT INSIDE IF + +----------------------+ +----------------------+ + | GigabitEthernet0/7/0 | | GigabitEthernet0/8/0 | + +----------------------+ +----------------------+ + NAT OUTSIDE IF NAT OUTSIDE IF + +----------------------+ +----------------------+ + | GigabitEthernet0/a/0 | | GigabitEthernet0/b/0 | + +----------------------+ +----------------------+ + VRF 2 VRF 3 + | | + +--------------------------+ + | + +------------+------------+------------+ + | | | | + +----------+ +----------+ +----------+ +----------+ + | 10.0.0.1 | | 10.0.0.2 | | 10.0.1.1 | | 10.0.1.2 | + +----------+ +----------+ +----------+ +----------+ + VRF 0 POOL VRF 1 POOL VRF 0 POOL VRF 1 POOL + +.. + + nat44 add address ``ip4-addr`` [tenant-vrf ``vrf-id``] [del] + + nat44 plugin enable inside-vrf ``vrf-id`` outside-vrf ``vrf-id`` + [disable]", + +Default behavior +^^^^^^^^^^^^^^^^ + +By design NAT supports passing communication between VRFs. Passing +communication between multiple different VRFs is also supported (GE0/7/0 +-> GE0/b/0, GE0/8/0 -> GE0/a/0). + +NAT pool address tenant-vrf configuration parameter is used to constrain +pool address to specific inside VRF. Example communication (in the above +diagram): 1) from GE0/7/0 -> GE0/b/0 would choose 10.0.1.1 pool address +2) from GE0/8/0 -> GE0/b/0 would choose 10.0.1.2 pool address + +Plugin enable parameters inside-vrf and outside-vrf are used as follows: + +Both ``inside-vrf`` and ``outside-vrf`` configuration parameters are +used in conjunction with Static NAT, inside-vrf is only used for Static +NAT. + +inside VRF: - used only in conjunction with static mappings - default +inside VRF parameter is used in in2out feature to lookup static mapping +if mapping can’t be found by inside interface VRF - used as default when +adding static mappings as in2out vrf + +outside VRF: - used in conjunction with static mappings - secondary +option for looking up static mappings in in2out feature based on outside +VRF - used as default destination vrf in in2out feature during session +creation if non of outside interfaces can resolve destination IP address + +Session creation default behavior (in2out only): - ingress interface fib +is used as inside fib - Outside fib is chosen based on ability to +resolve destination address in one of the outside interface networks. if +there is no such network that is able to resolve destination a default +outside fib (outside vrf index) is used. + +Default behavior enables use of multiple outside and inside fibs with +some limitations. The limitation in the default behavior is that if each +interface belonging to different fib contains default gateway every time +first interface network fib gets used as outside fib index during +session creation. + +VRF tables +^^^^^^^^^^ + + nat44 vrf table [add|del] ``vrf-id`` + +.. + + nat44 vrf route [add|del] table ``vrf-id`` ``vrf-id`` + +VRF tables change the default behavior of working with inter-vrf +communication. Adding empty VRF table disables passing communication +between VRFs. Adding additional routes to the table makes destination +VRF decision making algorithm do lookups into these tables. During +session creation destination VRF in in2out feature is resolved by +traversing VRF routes in the matching VRF table. If VRF route resolves +destination IPv4 address then this VRF gets used. If non VRF route can +resolve destination IPv4 address If VRF route can’t be found source VRF +will be used. Priority of VRF routes is based on order of configuration. + +Timeouts +~~~~~~~~ + + set nat timeout [udp ``sec`` \| tcp-established ``sec`` + tcp-transitory ``sec`` \| icmp ``sec`` \| reset] + +Session Limiting +~~~~~~~~~~~~~~~~ + + nat44 plugin enable sessions ``max-number`` + +Maximum number of sessions value is used on per-thread (per-worker) +basis. + + set nat44 session limit ``limit`` [vrf ``table-id``] + +Per-vrf session limiting makes it possible to split maximum number of +sessions between different VRFs. + +MSS Clamping +~~~~~~~~~~~~ + + nat mss-clamping ``mss-value``\ \|disable + +Forwarding +~~~~~~~~~~ + + nat44 forwarding enable|disable + +Additional Configuration Commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + | set nat frame-queue-nelts ``number`` + | set nat workers ``workers-list`` + | nat44 del session in|out ``addr``:``port`` tcp|udp|icmp [vrf + ``id``] [external-host ``addr``:``port``] + +Show commands +^^^^^^^^^^^^^ + +:: + + show nat workers + show nat timeouts + show nat44 summary + show nat44 sessions + show nat44 addresses + show nat mss-clamping + show nat44 interfaces + show nat44 vrf tables + show nat44 hash tables + nat44 show static mappings + show nat44 interface address + +Configuration Examples +---------------------- + +TWICE-NAT +~~~~~~~~~ + +Twice NAT lets you translate both the source and destination address in +a single rule. Currently, twice NAT44 is supported only for local +network service session initiated from outside network. Twice NAT static +mappings can only get initiated (create sessions) from outside network. + +Topology +^^^^^^^^ + +:: + + +--------------------------+ + | 10.0.0.2/24 (local host) | + +--------------------------+ + | + +---------------------------------+ + | 10.0.0.1/24 (eth0) (nat inside) | + | 20.0.0.1/24 (eth1) (nat outside)| + +---------------------------------+ + | + +---------------------------+ + | 20.0.0.2/24 (remote host) | + +---------------------------+ + +In this example traffic will be initiated from remote host. Remote host +will be accessing local host via twice-nat mapping. + +Translation will occur as follows: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +outside to inside translation: + + + | src address: 20.0.0.2 -> 192.168.160.101 + | dst address: 20.0.0.1 -> 10.0.0.2 + +inside to outside translation: + + + | src address: 10.0.0.2 -> 20.0.0.1 + | dst address: 192.168.160.101 -> 20.0.0.2 + +Configuration +^^^^^^^^^^^^^ + +Enable nat44-ed plugin: + + +:: + + nat44 plugin enable sessions 1000 + +Configure inside interface: + + +:: + + set int state eth0 up + set int ip address eth0 10.0.0.1/24 + set int nat44 in eth0 + +Configure outside interface: + + +:: + + set int state eth1 up + set int ip address eth1 20.0.0.1/24 + set int nat44 out eth1 + +Configure nat address pools: + + +:: + + nat44 add address 20.0.0.1 + nat44 add address 192.168.160.101 twice-nat + +- alternatively we could use ``nat44 add interface address eth1`` +- both pools are required +- pool ``20.0.0.1`` is used for out2in incoming traffic +- special twice-nat pool ``192.168.160.101`` is used for secondary + translation + +Finally, add twice-nat mapping: + + + nat44 add static mapping tcp local 10.0.0.2 5201 external 20.0.0.1 + 5201 twice-nat + +SELF TWICE-NAT +~~~~~~~~~~~~~~ + +Self twice NAT works similar to twice NAT with few exceptions. Self +twice NAT is a feature that lets client and service running on the same +host to communicate via NAT device. This means that external address is +the same address as local address. Self twice NAT static mappings can +only get initiated (create sessions) from outside network. + +.. _topology-self-twice-nat: + +Topology +^^^^^^^^ + +:: + + +--------------------------+ + | 10.0.0.2/24 (local host) | + +--------------------------+ + | + +-------------------------------------------+ + | 10.0.0.1/24 (eth0) (nat inside & outside) | + +-------------------------------------------+ + +In this example traffic will be initiated from local host. Local host +will be accessing itself via self-twice-nat mapping. + +.. _translation-will-occur-as-follows-1: + +Translation will occur as follows: +'''''''''''''''''''''''''''''''''' + +.. _outside-to-inside-translation-1: + +outside to inside translation: + + + | src address: 10.0.0.2 -> 192.168.160.101 + | dst address: 10.0.0.1 -> 10.0.0.2 + +.. _inside-to-outside-translation-1: + +inside to outside translation: + + + | src address: 10.0.0.2 -> 10.0.0.1 + | dst address: 192.168.160.101 -> 10.0.0.2 + +.. _configuration-1: + +Configuration +^^^^^^^^^^^^^ + +.. _enable-nat44-ed-plugin-1: + +Enable nat44-ed plugin: + + +:: + + nat44 plugin enable sessions 1000 + +Configure NAT interface: + + +:: + + set int state eth0 up + set int ip address eth0 10.0.0.1/24 + set int nat44 in eth0 + set int nat44 out eth0 + +.. _configure-nat-address-pools-1: + +Configure nat address pools: + + +:: + + nat44 add address 10.0.0.1 + nat44 add address 192.168.160.101 twice-nat + +Finally, add self-twice-nat mapping: + + + nat44 add static mapping tcp local 10.0.0.2 5201 external 10.0.0.1 + 5201 self-twice-nat diff --git a/src/plugins/nat/nat44-ed/nat44_ed_format.c b/src/plugins/nat/nat44-ed/nat44_ed_format.c index 81e743fd276..ee3e925e529 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_format.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_format.c @@ -12,57 +12,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @file - * @brief NAT formatting - */ #include <nat/nat44-ed/nat44_ed.h> #include <nat/nat44-ed/nat44_ed_inlines.h> u8 * -format_nat_addr_and_port_alloc_alg (u8 * s, va_list * args) +format_ed_session_kvp (u8 *s, va_list *args) { - u32 i = va_arg (*args, u32); - u8 *t = 0; + clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *); - switch (i) - { -#define _(v, N, s) case NAT_ADDR_AND_PORT_ALLOC_ALG_##N: t = (u8 *) s; break; - foreach_nat_addr_and_port_alloc_alg -#undef _ - default: - s = format (s, "unknown"); - return s; - } - s = format (s, "%s", t); - return s; -} + u8 proto; + u16 r_port, l_port; + ip4_address_t l_addr, r_addr; + u32 fib_index; -u8 * -format_snat_session_state (u8 * s, va_list * args) -{ - u32 i = va_arg (*args, u32); - u8 *t = 0; + split_ed_kv (v, &l_addr, &r_addr, &proto, &fib_index, &l_port, &r_port); + s = format (s, + "local %U:%d remote %U:%d proto %U fib %d thread-index %u " + "session-index %u", + format_ip4_address, &l_addr, clib_net_to_host_u16 (l_port), + format_ip4_address, &r_addr, clib_net_to_host_u16 (r_port), + format_ip_protocol, proto, fib_index, + ed_value_get_thread_index (v), ed_value_get_session_index (v)); - switch (i) - { -#define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break; - foreach_snat_session_state -#undef _ - default: - t = format (t, "unknown"); - } - s = format (s, "%s", t); return s; } u8 * format_snat_session (u8 * s, va_list * args) { + snat_main_t *sm = va_arg (*args, snat_main_t *); snat_main_per_thread_data_t *tsm = va_arg (*args, snat_main_per_thread_data_t *); snat_session_t *sess = va_arg (*args, snat_session_t *); + f64 now = va_arg (*args, f64); if (nat44_ed_is_unk_proto (sess->proto)) { @@ -103,8 +86,10 @@ format_snat_session (u8 * s, va_list * args) s = format (s, " o2i flow: %U\n", format_nat_6t_flow, &sess->o2i); s = format (s, " index %llu\n", sess - tsm->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); + s = format (s, " timeout in %.2f\n", + nat44_session_get_timeout (sm, sess) - (now - sess->last_heard)); + s = format (s, " total pkts %d, total bytes %lld\n", sess->total_pkts, + sess->total_bytes); if (nat44_ed_is_session_static (sess)) s = format (s, " static translation\n"); else @@ -188,7 +173,8 @@ format_snat_static_mapping (u8 * s, va_list * args) u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args) { - snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *); + snat_static_mapping_resolve_t *m = + va_arg (*args, snat_static_mapping_resolve_t *); vnet_main_t *vnm = vnet_get_main (); if (is_sm_addr_only (m->flags)) @@ -205,6 +191,131 @@ format_snat_static_map_to_resolve (u8 * s, va_list * args) return s; } +u8 * +format_nat_ed_translation_error (u8 *s, va_list *args) +{ + nat_translation_error_e e = va_arg (*args, nat_translation_error_e); + + switch (e) + { + case NAT_ED_TRNSL_ERR_SUCCESS: + s = format (s, "success"); + break; + case NAT_ED_TRNSL_ERR_TRANSLATION_FAILED: + s = format (s, "translation-failed"); + break; + case NAT_ED_TRNSL_ERR_FLOW_MISMATCH: + s = format (s, "flow-mismatch"); + break; + case NAT_ED_TRNSL_ERR_PACKET_TRUNCATED: + s = format (s, "packet-truncated"); + break; + case NAT_ED_TRNSL_ERR_INNER_IP_CORRUPT: + s = format (s, "inner-ip-corrupted"); + break; + case NAT_ED_TRNSL_ERR_INVALID_CSUM: + s = format (s, "invalid-checksum"); + break; + } + return s; +} + +u8 * +format_nat_6t_flow (u8 *s, va_list *args) +{ + nat_6t_flow_t *f = va_arg (*args, nat_6t_flow_t *); + + s = format (s, "match: %U ", format_nat_6t, &f->match); + int r = 0; + if (f->ops & NAT_FLOW_OP_SADDR_REWRITE) + { + s = format (s, "rewrite: saddr %U ", format_ip4_address, + f->rewrite.saddr.as_u8); + r = 1; + } + if (f->ops & NAT_FLOW_OP_SPORT_REWRITE) + { + if (!r) + { + s = format (s, "rewrite: "); + r = 1; + } + s = format (s, "sport %u ", clib_net_to_host_u16 (f->rewrite.sport)); + } + if (f->ops & NAT_FLOW_OP_DADDR_REWRITE) + { + if (!r) + { + s = format (s, "rewrite: "); + r = 1; + } + s = format (s, "daddr %U ", format_ip4_address, f->rewrite.daddr.as_u8); + } + if (f->ops & NAT_FLOW_OP_DPORT_REWRITE) + { + if (!r) + { + s = format (s, "rewrite: "); + r = 1; + } + s = format (s, "dport %u ", clib_net_to_host_u16 (f->rewrite.dport)); + } + if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE) + { + if (!r) + { + s = format (s, "rewrite: "); + r = 1; + } + s = format (s, "icmp-id %u ", clib_net_to_host_u16 (f->rewrite.icmp_id)); + } + if (f->ops & NAT_FLOW_OP_TXFIB_REWRITE) + { + if (!r) + { + s = format (s, "rewrite: "); + r = 1; + } + s = format (s, "txfib %u ", f->rewrite.fib_index); + } + return s; +} + +u8 * +format_nat_6t (u8 *s, va_list *args) +{ + nat_6t_t *t = va_arg (*args, nat_6t_t *); + + s = format (s, "saddr %U sport %u daddr %U dport %u proto %U fib_idx %u", + format_ip4_address, t->saddr.as_u8, + clib_net_to_host_u16 (t->sport), format_ip4_address, + t->daddr.as_u8, clib_net_to_host_u16 (t->dport), + format_ip_protocol, t->proto, t->fib_index); + return s; +} + +u8 * +format_nat44_ed_tcp_state (u8 *s, va_list *args) +{ + nat44_ed_tcp_state_e e = va_arg (*args, nat44_ed_tcp_state_e); + switch (e) + { + case NAT44_ED_TCP_STATE_CLOSED: + s = format (s, "closed"); + break; + case NAT44_ED_TCP_STATE_ESTABLISHED: + s = format (s, "established"); + break; + case NAT44_ED_TCP_STATE_CLOSING: + s = format (s, "closing"); + break; + case NAT44_ED_TCP_N_STATE: + s = format (s, "BUG! unexpected N_STATE! BUG!"); + break; + } + return s; +} + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/nat/nat44-ed/nat44_ed_handoff.c b/src/plugins/nat/nat44-ed/nat44_ed_handoff.c index c5ceff4e454..5cb4effb6c4 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_handoff.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_handoff.c @@ -19,7 +19,6 @@ #include <vlib/vlib.h> #include <vnet/vnet.h> -#include <vnet/handoff.h> #include <vnet/fib/ip4_fib.h> #include <vppinfra/error.h> diff --git a/src/plugins/nat/nat44-ed/nat44_ed_in2out.c b/src/plugins/nat/nat44-ed/nat44_ed_in2out.c index 73dacce57e6..9b4dac3b356 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_in2out.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_in2out.c @@ -49,6 +49,7 @@ typedef struct u8 is_slow_path; u8 translation_via_i2of; u8 lookup_skipped; + u8 tcp_state; } nat_in2out_ed_trace_t; static u8 * @@ -78,7 +79,7 @@ format_nat_in2out_ed_trace (u8 * s, va_list * args) { if (t->lookup_skipped) { - s = format (s, "\n lookup skipped - cached session index used"); + s = format (s, "\n lookup skipped - cached session index used"); } else { @@ -86,76 +87,13 @@ format_nat_in2out_ed_trace (u8 * s, va_list * args) &t->search_key); } } - - return s; -} - -/** - * @brief Check if packet should be translated - * - * Packets aimed at outside interface and external address with active session - * should be translated. - * - * @param sm NAT main - * @param rt NAT runtime data - * @param sw_if_index0 index of the inside interface - * @param ip0 IPv4 header - * @param rx_fib_index0 RX FIB index - * - * @returns 0 if packet should be translated otherwise 1 - */ -static inline int -snat_not_translate_fast (snat_main_t *sm, vlib_node_runtime_t *node, - u32 sw_if_index0, ip4_header_t *ip0, - u32 rx_fib_index0) -{ - fib_node_index_t fei = FIB_NODE_INDEX_INVALID; - nat_outside_fib_t *outside_fib; - fib_prefix_t pfx = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 32, - .fp_addr = { - .ip4.as_u32 = ip0->dst_address.as_u32, - } - , - }; - - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE ( - is_interface_addr (sm, node, sw_if_index0, ip0->dst_address.as_u32))) - return 1; - - fei = fib_table_lookup (rx_fib_index0, &pfx); - if (FIB_NODE_INDEX_INVALID != fei) + if (IP_PROTOCOL_TCP == t->i2of.match.proto) { - u32 sw_if_index = fib_entry_get_resolving_interface (fei); - if (sw_if_index == ~0) - { - vec_foreach (outside_fib, sm->outside_fibs) - { - fei = fib_table_lookup (outside_fib->fib_index, &pfx); - if (FIB_NODE_INDEX_INVALID != fei) - { - sw_if_index = fib_entry_get_resolving_interface (fei); - if (sw_if_index != ~0) - break; - } - } - } - if (sw_if_index == ~0) - return 1; - - snat_interface_t *i; - pool_foreach (i, sm->interfaces) - { - /* NAT packet aimed at outside interface */ - if ((nat44_ed_is_interface_outside (i)) && - (sw_if_index == i->sw_if_index)) - return 0; - } + s = format (s, "\n TCP state: %U", format_nat44_ed_tcp_state, + t->tcp_state); } - return 1; + return s; } static int @@ -164,14 +102,18 @@ nat_ed_alloc_addr_and_port_with_snat_address ( u16 port_per_thread, u32 snat_thread_index, snat_session_t *s, ip4_address_t *outside_addr, u16 *outside_port) { - const u16 port_thread_offset = (port_per_thread * snat_thread_index) + 1024; + const u16 port_thread_offset = + (port_per_thread * snat_thread_index) + ED_USER_PORT_OFFSET; + + /* Backup original match in case of failure */ + const nat_6t_t match = s->o2i.match; s->o2i.match.daddr = a->addr; /* first try port suggested by caller */ u16 port = clib_net_to_host_u16 (*outside_port); u16 port_offset = port - port_thread_offset; - if (port <= port_thread_offset || - port > port_thread_offset + port_per_thread) + if (port < port_thread_offset || + port >= port_thread_offset + port_per_thread) { /* need to pick a different port, suggested port doesn't fit in * this thread's port range */ @@ -197,54 +139,138 @@ nat_ed_alloc_addr_and_port_with_snat_address ( --attempts; } while (attempts > 0); + + /* Revert match */ + s->o2i.match = match; return 1; } static int -nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, u32 nat_proto, +nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, + u32 tx_sw_if_index, u32 nat_proto, u32 thread_index, ip4_address_t s_addr, - u32 snat_thread_index, snat_session_t *s, - ip4_address_t *outside_addr, u16 *outside_port) + ip4_address_t d_addr, u32 snat_thread_index, + snat_session_t *s, ip4_address_t *outside_addr, + u16 *outside_port) { - int i; - snat_address_t *a, *ga = 0; - if (vec_len (sm->addresses) > 0) { - u32 s_addr_offset = s_addr.as_u32 % vec_len (sm->addresses); - - for (i = s_addr_offset; i < vec_len (sm->addresses); ++i) + u32 s_addr_offset = (s_addr.as_u32 + (s_addr.as_u32 >> 8) + + (s_addr.as_u32 >> 16) + (s_addr.as_u32 >> 24)) % + vec_len (sm->addresses); + snat_address_t *a, *ja = 0, *ra = 0, *ba = 0; + int i; + + // output feature + if (tx_sw_if_index != ~0) { - a = sm->addresses + i; - if (a->fib_index == rx_fib_index) + for (i = s_addr_offset; i < vec_len (sm->addresses); ++i) { - return nat_ed_alloc_addr_and_port_with_snat_address ( - sm, nat_proto, thread_index, a, sm->port_per_thread, - snat_thread_index, s, outside_addr, outside_port); + a = sm->addresses + i; + if (a->fib_index == rx_fib_index) + { + if (a->sw_if_index == tx_sw_if_index) + { + if ((a->addr_len != ~0) && + (a->net.as_u32 == + (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len]))) + + { + return nat_ed_alloc_addr_and_port_with_snat_address ( + sm, nat_proto, thread_index, a, + sm->port_per_thread, snat_thread_index, s, + outside_addr, outside_port); + } + ra = a; + } + ja = a; + } + else if (a->fib_index == ~0) + { + ba = a; + } } - else if (a->fib_index == ~0) + for (i = 0; i < s_addr_offset; ++i) { - ga = a; + a = sm->addresses + i; + if (a->fib_index == rx_fib_index) + { + if (a->sw_if_index == tx_sw_if_index) + { + if ((a->addr_len != ~0) && + (a->net.as_u32 == + (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len]))) + + { + return nat_ed_alloc_addr_and_port_with_snat_address ( + sm, nat_proto, thread_index, a, + sm->port_per_thread, snat_thread_index, s, + outside_addr, outside_port); + } + ra = a; + } + ja = a; + } + else if (a->fib_index == ~0) + { + ba = a; + } } - } - - for (i = 0; i < s_addr_offset; ++i) - { - a = sm->addresses + i; - if (a->fib_index == rx_fib_index) + if (ra) { return nat_ed_alloc_addr_and_port_with_snat_address ( - sm, nat_proto, thread_index, a, sm->port_per_thread, + sm, nat_proto, thread_index, ra, sm->port_per_thread, snat_thread_index, s, outside_addr, outside_port); } - else if (a->fib_index == ~0) + } + else + { + // first try nat pool addresses to sw interface addreses mappings + for (i = s_addr_offset; i < vec_len (sm->addresses); ++i) { - ga = a; + a = sm->addresses + i; + if (a->fib_index == rx_fib_index) + { + if ((a->addr_len != ~0) && + (a->net.as_u32 == + (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len]))) + { + return nat_ed_alloc_addr_and_port_with_snat_address ( + sm, nat_proto, thread_index, a, sm->port_per_thread, + snat_thread_index, s, outside_addr, outside_port); + } + ja = a; + } + else if (a->fib_index == ~0) + { + ba = a; + } + } + for (i = 0; i < s_addr_offset; ++i) + { + a = sm->addresses + i; + if (a->fib_index == rx_fib_index) + { + if ((a->addr_len != ~0) && + (a->net.as_u32 == + (d_addr.as_u32 & ip4_main.fib_masks[a->addr_len]))) + { + return nat_ed_alloc_addr_and_port_with_snat_address ( + sm, nat_proto, thread_index, a, sm->port_per_thread, + snat_thread_index, s, outside_addr, outside_port); + } + ja = a; + } + else if (a->fib_index == ~0) + { + ba = a; + } } } - if (ga) + if (ja || ba) { + a = ja ? ja : ba; return nat_ed_alloc_addr_and_port_with_snat_address ( sm, nat_proto, thread_index, a, sm->port_per_thread, snat_thread_index, s, outside_addr, outside_port); @@ -255,32 +281,6 @@ nat_ed_alloc_addr_and_port (snat_main_t *sm, u32 rx_fib_index, u32 nat_proto, return 1; } -static_always_inline u32 -nat_outside_fib_index_lookup (snat_main_t * sm, ip4_address_t addr) -{ - fib_node_index_t fei = FIB_NODE_INDEX_INVALID; - nat_outside_fib_t *outside_fib; - fib_prefix_t pfx = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 32, - .fp_addr = {.ip4.as_u32 = addr.as_u32,} - , - }; - // TODO: multiple vrfs none can resolve addr - vec_foreach (outside_fib, sm->outside_fibs) - { - fei = fib_table_lookup (outside_fib->fib_index, &pfx); - if (FIB_NODE_INDEX_INVALID != fei) - { - if (fib_entry_get_resolving_interface (fei) != ~0) - { - return outside_fib->fib_index; - } - } - } - return ~0; -} - static_always_inline int nat44_ed_external_sm_lookup (snat_main_t *sm, ip4_address_t match_addr, u16 match_port, ip_protocol_t match_protocol, @@ -304,17 +304,142 @@ nat44_ed_external_sm_lookup (snat_main_t *sm, ip4_address_t match_addr, return 1; } +static_always_inline vrf_table_t * +get_vrf_table_by_fib (u32 fib_index) +{ + snat_main_t *sm = &snat_main; + vrf_table_t *t; + + pool_foreach (t, sm->vrf_tables) + { + if (fib_index == t->table_fib_index) + { + return t; + } + } + + return 0; +} + +static_always_inline u32 +get_tx_fib_index (u32 rx_fib_index, ip4_address_t addr) +{ + fib_node_index_t fei = FIB_NODE_INDEX_INVALID; + fib_prefix_t pfx = { + .fp_proto = FIB_PROTOCOL_IP4, + .fp_len = 32, + .fp_addr = {.ip4.as_u32 = addr.as_u32,} + , + }; + + snat_main_t *sm = &snat_main; + vrf_table_t *t = get_vrf_table_by_fib (rx_fib_index); + // default to rx fib + u32 tx_fib_index = rx_fib_index; + + if (0 != t) + { + // managed routes to other fibs + vrf_route_t *r; + pool_foreach (r, t->routes) + { + fei = fib_table_lookup (r->fib_index, &pfx); + if ((FIB_NODE_INDEX_INVALID != fei) && + (~0 != fib_entry_get_resolving_interface (fei))) + { + tx_fib_index = r->fib_index; + break; + } + } + } + else + { + // default to configured fib + tx_fib_index = sm->outside_fib_index; + + // default routes to other fibs + nat_fib_t *f; + vec_foreach (f, sm->outside_fibs) + { + fei = fib_table_lookup (f->fib_index, &pfx); + if ((FIB_NODE_INDEX_INVALID != fei) && + (~0 != fib_entry_get_resolving_interface (fei))) + { + tx_fib_index = f->fib_index; + break; + } + } + } + + return tx_fib_index; +} + +static_always_inline int +is_destination_resolvable (u32 rx_fib_index, ip4_address_t addr) +{ + fib_node_index_t fei = FIB_NODE_INDEX_INVALID; + fib_prefix_t pfx = { + .fp_proto = FIB_PROTOCOL_IP4, + .fp_len = 32, + .fp_addr = {.ip4.as_u32 = addr.as_u32,} + , + }; + + snat_main_t *sm = &snat_main; + vrf_table_t *t = get_vrf_table_by_fib (rx_fib_index); + u32 ii; + + if (0 != t) + { + // managed routes to other fibs + vrf_route_t *r; + pool_foreach (r, t->routes) + { + fei = fib_table_lookup (r->fib_index, &pfx); + if ((FIB_NODE_INDEX_INVALID != fei) && + (~0 != (ii = fib_entry_get_resolving_interface (fei)))) + { + return 1; + } + } + } + else + { + // default routes to other fibs + nat_fib_t *f; + vec_foreach (f, sm->outside_fibs) + { + fei = fib_table_lookup (f->fib_index, &pfx); + if ((FIB_NODE_INDEX_INVALID != fei) && + (~0 != (ii = fib_entry_get_resolving_interface (fei)))) + { + snat_interface_t *i; + pool_foreach (i, sm->interfaces) + { + if ((nat44_ed_is_interface_outside (i)) && + (ii == i->sw_if_index)) + { + return 1; + } + } + } + } + } + + return 0; +} + static u32 slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, ip4_address_t l_addr, ip4_address_t r_addr, u16 l_port, - u16 r_port, u8 proto, u32 rx_fib_index, + u16 r_port, u8 proto, u32 rx_fib_index, u32 tx_sw_if_index, snat_session_t **sessionp, vlib_node_runtime_t *node, u32 next, u32 thread_index, f64 now) { snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; ip4_address_t outside_addr; u16 outside_port; - u32 outside_fib_index; + u32 tx_fib_index; u8 is_identity_nat = 0; snat_session_t *s = NULL; @@ -335,33 +460,14 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, } } - outside_fib_index = sm->outside_fib_index; - - switch (vec_len (sm->outside_fibs)) - { - case 0: - outside_fib_index = sm->outside_fib_index; - break; - case 1: - outside_fib_index = sm->outside_fibs[0].fib_index; - break; - default: - outside_fib_index = nat_outside_fib_index_lookup (sm, r_addr); - break; - } - ip4_address_t sm_addr; u16 sm_port; u32 sm_fib_index; - /* First try to match static mapping by local address and port */ - int is_sm; - if (snat_static_mapping_match (vm, sm, l_addr, l_port, rx_fib_index, proto, - &sm_addr, &sm_port, &sm_fib_index, 0, 0, 0, - &lb, 0, &is_identity_nat, 0)) - { - is_sm = 0; - } - else + int is_sm = 0; + // First try to match static mapping by local address and port + if (!snat_static_mapping_match (vm, l_addr, l_port, rx_fib_index, proto, + &sm_addr, &sm_port, &sm_fib_index, 0, 0, 0, + &lb, 0, &is_identity_nat, 0)) { if (PREDICT_FALSE (is_identity_nat)) { @@ -384,21 +490,24 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, s = nat_ed_session_alloc (sm, thread_index, now, proto); ASSERT (s); + tx_fib_index = get_tx_fib_index (rx_fib_index, r_addr); + if (!is_sm) { s->in2out.addr = l_addr; s->in2out.port = l_port; s->proto = proto; s->in2out.fib_index = rx_fib_index; - s->out2in.fib_index = outside_fib_index; + s->out2in.fib_index = tx_fib_index; // suggest using local port to allocation function outside_port = l_port; - // hairpinning? - int is_hairpinning = nat44_ed_external_sm_lookup (sm, r_addr, r_port, - proto, &daddr, &dport); - s->flags |= is_hairpinning * SNAT_SESSION_FLAG_HAIRPINNING; + if (PREDICT_FALSE (nat44_ed_external_sm_lookup (sm, r_addr, r_port, + proto, &daddr, &dport))) + { + s->flags |= SNAT_SESSION_FLAG_HAIRPINNING; + } // destination addr/port updated with real values in // nat_ed_alloc_addr_and_port @@ -414,10 +523,11 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, nat_6t_flow_dport_rewrite_set (&s->o2i, l_port); } nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index); + nat_6t_flow_saddr_rewrite_set (&s->o2i, r_addr.as_u32); - if (nat_ed_alloc_addr_and_port (sm, rx_fib_index, proto, thread_index, - l_addr, tsm->snat_thread_index, s, - &outside_addr, &outside_port)) + if (nat_ed_alloc_addr_and_port ( + sm, rx_fib_index, tx_sw_if_index, proto, thread_index, l_addr, + r_addr, tsm->snat_thread_index, s, &outside_addr, &outside_port)) { nat_elog_notice (sm, "addresses exhausted"); b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS]; @@ -436,7 +546,7 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, s->in2out.port = l_port; s->proto = proto; s->in2out.fib_index = rx_fib_index; - s->out2in.fib_index = outside_fib_index; + s->out2in.fib_index = tx_fib_index; s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING; // hairpinning? @@ -458,6 +568,7 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, } nat_6t_flow_daddr_rewrite_set (&s->o2i, l_addr.as_u32); nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index); + nat_6t_flow_saddr_rewrite_set (&s->o2i, r_addr.as_u32); if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 2)) { nat_elog_notice (sm, "out2in key add failed"); @@ -484,7 +595,7 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, nat_6t_flow_sport_rewrite_set (&s->i2o, outside_port); nat_6t_flow_dport_rewrite_set (&s->i2o, dport); } - nat_6t_flow_txfib_rewrite_set (&s->i2o, outside_fib_index); + nat_6t_flow_txfib_rewrite_set (&s->i2o, tx_fib_index); if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 1)) { @@ -516,38 +627,55 @@ error: } static_always_inline int -nat44_ed_not_translate (vlib_main_t *vm, snat_main_t *sm, - vlib_node_runtime_t *node, u32 sw_if_index, - vlib_buffer_t *b, ip4_header_t *ip, u32 proto, - u32 rx_fib_index) +nat44_ed_not_translate (vlib_main_t *vm, vlib_node_runtime_t *node, + u32 sw_if_index, vlib_buffer_t *b, ip4_header_t *ip, + u32 proto, u32 rx_fib_index) { + snat_main_t *sm = &snat_main; + clib_bihash_kv_16_8_t kv, value; + ip4_address_t placeholder_addr; + u32 placeholder_fib_index; + u16 placeholder_port; init_ed_k (&kv, ip->dst_address.as_u32, vnet_buffer (b)->ip.reass.l4_dst_port, ip->src_address.as_u32, vnet_buffer (b)->ip.reass.l4_src_port, sm->outside_fib_index, ip->protocol); - /* NAT packet aimed at external address if has active sessions */ - if (clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value)) + // do nat if active session or is static mapping + if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value) || + !snat_static_mapping_match ( + vm, ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port, + sm->outside_fib_index, proto, &placeholder_addr, &placeholder_port, + &placeholder_fib_index, 1, 0, 0, 0, 0, 0, 0)) { - /* or is static mappings */ - ip4_address_t placeholder_addr; - u16 placeholder_port; - u32 placeholder_fib_index; - if (!snat_static_mapping_match ( - vm, sm, ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port, - sm->outside_fib_index, proto, &placeholder_addr, &placeholder_port, - &placeholder_fib_index, 1, 0, 0, 0, 0, 0, 0)) - return 0; + return 0; } - else - return 0; + // do not nat if forwarding enabled if (sm->forwarding_enabled) - return 1; + { + return 1; + } + + // do not nat packet aimed at the interface address + if (PREDICT_FALSE ( + is_interface_addr (sm, node, sw_if_index, ip->dst_address.as_u32))) + { + return 1; + } - return snat_not_translate_fast (sm, node, sw_if_index, ip, rx_fib_index); + // do nat packets with resolvable destination + // destination can be resolved either by: + // a) vrf routing table entry + // b) (non output feature) outside interface fib + if (is_destination_resolvable (rx_fib_index, ip->dst_address)) + { + return 0; + } + + return 1; } static_always_inline int @@ -597,7 +725,9 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, { if (ip->protocol == IP_PROTOCOL_TCP) { - nat44_set_tcp_session_state_i2o (sm, now, s, b, thread_index); + nat44_set_tcp_session_state_i2o ( + sm, now, s, vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags, + thread_index); } /* Accounting */ nat44_session_update_counters (s, now, @@ -619,7 +749,7 @@ nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, u16 src_port, u16 dst_port, u32 thread_index, u32 rx_sw_if_index, u32 tx_sw_if_index, - f64 now, int is_multi_worker) + int is_multi_worker) { clib_bihash_kv_16_8_t kv, value; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; @@ -637,12 +767,6 @@ nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b, s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value)); - if (nat44_is_ses_closed (s) - && (!s->tcp_closed_timestamp || now >= s->tcp_closed_timestamp)) - { - nat44_ed_free_session_data (sm, s, thread_index, 0); - nat_ed_session_delete (sm, s, thread_index, 1); - } return 1; } @@ -682,11 +806,11 @@ nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b, /* hairpinning */ pool_foreach (i, sm->output_feature_interfaces) - { - if ((nat44_ed_is_interface_inside (i)) && - (rx_sw_if_index == i->sw_if_index)) - return 0; - } + { + if ((nat44_ed_is_interface_inside (i)) && + (rx_sw_if_index == i->sw_if_index)) + return 0; + } return 1; } @@ -696,9 +820,10 @@ nat44_ed_not_translate_output_feature (snat_main_t *sm, vlib_buffer_t *b, static inline u32 icmp_in2out_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, icmp46_header_t *icmp, u32 sw_if_index, - u32 rx_fib_index, vlib_node_runtime_t *node, - u32 next, f64 now, u32 thread_index, - snat_session_t **s_p, int is_multi_worker) + u32 tx_sw_if_index, u32 rx_fib_index, + vlib_node_runtime_t *node, u32 next, f64 now, + u32 thread_index, snat_session_t **s_p, + int is_multi_worker) { vlib_main_t *vm = vlib_get_main (); u16 checksum; @@ -717,11 +842,11 @@ icmp_in2out_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, return NAT_NEXT_DROP; } - if (vnet_buffer (b)->sw_if_index[VLIB_TX] != ~0) + if (tx_sw_if_index != ~0) { if (PREDICT_FALSE (nat44_ed_not_translate_output_feature ( sm, b, ip, lookup_sport, lookup_dport, thread_index, sw_if_index, - vnet_buffer (b)->sw_if_index[VLIB_TX], now, is_multi_worker))) + tx_sw_if_index, is_multi_worker))) { return next; } @@ -729,7 +854,7 @@ icmp_in2out_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, else { if (PREDICT_FALSE (nat44_ed_not_translate ( - vm, sm, node, sw_if_index, b, ip, IP_PROTOCOL_ICMP, rx_fib_index))) + vm, node, sw_if_index, b, ip, IP_PROTOCOL_ICMP, rx_fib_index))) { return next; } @@ -742,9 +867,10 @@ icmp_in2out_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, return NAT_NEXT_DROP; } - next = slow_path_ed (vm, sm, b, ip->src_address, ip->dst_address, - lookup_sport, lookup_dport, ip->protocol, rx_fib_index, - &s, node, next, thread_index, vlib_time_now (vm)); + next = + slow_path_ed (vm, sm, b, ip->src_address, ip->dst_address, lookup_sport, + lookup_dport, ip->protocol, rx_fib_index, tx_sw_if_index, &s, + node, next, thread_index, vlib_time_now (vm)); if (NAT_NEXT_DROP == next) goto out; @@ -786,7 +912,7 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, snat_static_mapping_t *m = NULL; snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; snat_session_t *s = NULL; - u32 outside_fib_index = sm->outside_fib_index; + u32 tx_fib_index; int i; ip4_address_t new_src_addr = { 0 }; ip4_address_t new_dst_addr = ip->dst_address; @@ -801,20 +927,9 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, return 0; } - switch (vec_len (sm->outside_fibs)) - { - case 0: - outside_fib_index = sm->outside_fib_index; - break; - case 1: - outside_fib_index = sm->outside_fibs[0].fib_index; - break; - default: - outside_fib_index = nat_outside_fib_index_lookup (sm, ip->dst_address); - break; - } + tx_fib_index = get_tx_fib_index (rx_fib_index, ip->dst_address); - /* Try to find static mapping first */ + // Try to find static mapping first m = nat44_ed_sm_i2o_lookup (sm, ip->src_address, 0, rx_fib_index, ip->protocol); if (m) @@ -828,7 +943,7 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32) { init_ed_k (&s_kv, s->out2in.addr.as_u32, 0, - ip->dst_address.as_u32, 0, outside_fib_index, + ip->dst_address.as_u32, 0, tx_fib_index, ip->protocol); if (clib_bihash_search_16_8 (&sm->flow_hash, &s_kv, &s_value)) { @@ -843,7 +958,7 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, for (i = 0; i < vec_len (sm->addresses); i++) { init_ed_k (&s_kv, sm->addresses[i].addr.as_u32, 0, - ip->dst_address.as_u32, 0, outside_fib_index, + ip->dst_address.as_u32, 0, tx_fib_index, ip->protocol); if (clib_bihash_search_16_8 (&sm->flow_hash, &s_kv, &s_value)) { @@ -870,7 +985,7 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, nat_6t_i2o_flow_init (sm, thread_index, s, ip->src_address, 0, ip->dst_address, 0, rx_fib_index, ip->protocol); nat_6t_flow_saddr_rewrite_set (&s->i2o, new_src_addr.as_u32); - nat_6t_flow_txfib_rewrite_set (&s->i2o, outside_fib_index); + nat_6t_flow_txfib_rewrite_set (&s->i2o, tx_fib_index); // hairpinning? int is_hairpinning = nat44_ed_external_sm_lookup ( @@ -878,17 +993,17 @@ nat44_ed_in2out_slowpath_unknown_proto (snat_main_t *sm, vlib_buffer_t *b, s->flags |= is_hairpinning * SNAT_SESSION_FLAG_HAIRPINNING; nat_6t_flow_daddr_rewrite_set (&s->i2o, new_dst_addr.as_u32); - nat_6t_flow_txfib_rewrite_set (&s->i2o, outside_fib_index); + nat_6t_flow_txfib_rewrite_set (&s->i2o, tx_fib_index); nat_6t_o2i_flow_init (sm, thread_index, s, new_dst_addr, 0, new_src_addr, 0, - outside_fib_index, ip->protocol); + tx_fib_index, ip->protocol); nat_6t_flow_saddr_rewrite_set (&s->o2i, ip->dst_address.as_u32); nat_6t_flow_daddr_rewrite_set (&s->o2i, ip->src_address.as_u32); nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index); s->ext_host_addr.as_u32 = ip->dst_address.as_u32; s->out2in.addr.as_u32 = new_src_addr.as_u32; - s->out2in.fib_index = outside_fib_index; + s->out2in.fib_index = tx_fib_index; s->in2out.addr.as_u32 = ip->src_address.as_u32; s->in2out.fib_index = rx_fib_index; s->in2out.port = s->out2in.port = ip->protocol; @@ -951,7 +1066,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, ip_protocol_t proto0; ip4_header_t *ip0; snat_session_t *s0 = 0; - clib_bihash_kv_16_8_t kv0, value0; + clib_bihash_kv_16_8_t kv0 = { 0 }, value0; nat_translation_error_e translation_error = NAT_ED_TRNSL_ERR_SUCCESS; nat_6t_flow_t *f = 0; nat_6t_t lookup; @@ -1089,23 +1204,8 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, // session is closed, go slow path nat44_ed_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); - next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH; - goto trace0; - } - - if (s0->tcp_closed_timestamp) - { - if (now >= s0->tcp_closed_timestamp) - { - // session is closed, go slow path, freed in slow path - next[0] = def_slow; - } - else - { - // session in transitory timeout, drop - b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TCP_CLOSED]; - next[0] = NAT_NEXT_DROP; - } + s0 = 0; + next[0] = def_slow; goto trace0; } @@ -1117,6 +1217,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, { nat44_ed_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); + s0 = 0; // session is closed, go slow path next[0] = def_slow; goto trace0; @@ -1138,6 +1239,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, translation_error = NAT_ED_TRNSL_ERR_FLOW_MISMATCH; nat44_ed_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); + s0 = 0; next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED]; goto trace0; @@ -1149,6 +1251,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, { nat44_ed_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); + s0 = 0; next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED]; goto trace0; @@ -1159,7 +1262,9 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, case IP_PROTOCOL_TCP: vlib_increment_simple_counter (&sm->counters.fastpath.in2out.tcp, thread_index, cntr_sw_if_index0, 1); - nat44_set_tcp_session_state_i2o (sm, now, s0, b0, thread_index); + nat44_set_tcp_session_state_i2o ( + sm, now, s0, vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags, + thread_index); break; case IP_PROTOCOL_UDP: vlib_increment_simple_counter (&sm->counters.fastpath.in2out.udp, @@ -1202,6 +1307,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t *vm, clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of)); clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if)); t->translation_via_i2of = (&s0->i2o == f); + t->tcp_state = s0->tcp_state; } else { @@ -1255,7 +1361,7 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, udp_header_t *udp0; icmp46_header_t *icmp0; snat_session_t *s0 = 0; - clib_bihash_kv_16_8_t kv0, value0; + clib_bihash_kv_16_8_t kv0 = { 0 }, value0; int translation_error = NAT_ED_TRNSL_ERR_SUCCESS; b0 = *b; @@ -1303,6 +1409,7 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, { nat44_ed_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); + s0 = 0; next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED]; goto trace0; @@ -1316,8 +1423,9 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, if (PREDICT_FALSE (proto0 == IP_PROTOCOL_ICMP)) { next[0] = icmp_in2out_ed_slow_path ( - sm, b0, ip0, icmp0, rx_sw_if_index0, rx_fib_index0, node, next[0], - now, thread_index, &s0, is_multi_worker); + sm, b0, ip0, icmp0, rx_sw_if_index0, tx_sw_if_index0, + rx_fib_index0, node, next[0], now, thread_index, &s0, + is_multi_worker); if (NAT_NEXT_DROP != next[0] && s0 && NAT_ED_TRNSL_ERR_SUCCESS != (translation_error = nat_6t_flow_buf_translate_i2o ( @@ -1325,13 +1433,18 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, { nat44_ed_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); + s0 = 0; next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED]; goto trace0; } - vlib_increment_simple_counter (&sm->counters.slowpath.in2out.icmp, - thread_index, cntr_sw_if_index0, 1); + if (NAT_NEXT_DROP != next[0]) + { + vlib_increment_simple_counter ( + &sm->counters.slowpath.in2out.icmp, thread_index, + cntr_sw_if_index0, 1); + } goto trace0; } @@ -1345,13 +1458,6 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, s0 = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value0)); - - if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp) - { - nat44_ed_free_session_data (sm, s0, thread_index, 0); - nat_ed_session_delete (sm, s0, thread_index, 1); - s0 = NULL; - } } if (!s0) @@ -1361,7 +1467,7 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, if (PREDICT_FALSE (nat44_ed_not_translate_output_feature ( sm, b0, ip0, vnet_buffer (b0)->ip.reass.l4_src_port, vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index, - rx_sw_if_index0, tx_sw_if_index0, now, is_multi_worker))) + rx_sw_if_index0, tx_sw_if_index0, is_multi_worker))) goto trace0; /* @@ -1378,16 +1484,17 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, else { if (PREDICT_FALSE ( - nat44_ed_not_translate (vm, sm, node, rx_sw_if_index0, b0, - ip0, proto0, rx_fib_index0))) + nat44_ed_not_translate (vm, node, rx_sw_if_index0, b0, ip0, + proto0, rx_fib_index0))) goto trace0; } - next[0] = slow_path_ed ( - vm, sm, b0, ip0->src_address, ip0->dst_address, - vnet_buffer (b0)->ip.reass.l4_src_port, - vnet_buffer (b0)->ip.reass.l4_dst_port, ip0->protocol, - rx_fib_index0, &s0, node, next[0], thread_index, now); + next[0] = + slow_path_ed (vm, sm, b0, ip0->src_address, ip0->dst_address, + vnet_buffer (b0)->ip.reass.l4_src_port, + vnet_buffer (b0)->ip.reass.l4_dst_port, + ip0->protocol, rx_fib_index0, tx_sw_if_index0, &s0, + node, next[0], thread_index, now); if (PREDICT_FALSE (next[0] == NAT_NEXT_DROP)) goto trace0; @@ -1405,6 +1512,7 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, { nat44_ed_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); + s0 = 0; next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TRNSL_FAILED]; goto trace0; @@ -1414,7 +1522,9 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, { vlib_increment_simple_counter (&sm->counters.slowpath.in2out.tcp, thread_index, cntr_sw_if_index0, 1); - nat44_set_tcp_session_state_i2o (sm, now, s0, b0, thread_index); + nat44_set_tcp_session_state_i2o ( + sm, now, s0, vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags, + thread_index); } else { @@ -1447,6 +1557,7 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t *vm, clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of)); clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if)); t->translation_via_i2of = 1; + t->tcp_state = s0->tcp_state; } else diff --git a/src/plugins/nat/nat44-ed/nat44_ed_inlines.h b/src/plugins/nat/nat44-ed/nat44_ed_inlines.h index cb418960249..04e5236b7f9 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_inlines.h +++ b/src/plugins/nat/nat44-ed/nat44_ed_inlines.h @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + /** * @brief The NAT inline functions */ @@ -24,6 +25,7 @@ #include <vnet/fib/ip4_fib.h> #include <nat/lib/log.h> +#include <nat/lib/ipfix_logging.h> #include <nat/nat44-ed/nat44_ed.h> always_inline void @@ -123,13 +125,13 @@ nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0, u16 *lookup_dport, u8 *lookup_protocol) { icmp46_header_t *icmp0; - icmp_echo_header_t *echo0, *inner_echo0 = 0; + nat_icmp_echo_header_t *echo0, *inner_echo0 = 0; ip4_header_t *inner_ip0 = 0; void *l4_header = 0; icmp46_header_t *inner_icmp0; icmp0 = (icmp46_header_t *) ip4_next_header (ip0); - echo0 = (icmp_echo_header_t *) (icmp0 + 1); + echo0 = (nat_icmp_echo_header_t *) (icmp0 + 1); // avoid warning about unused variables in caller by setting to bogus values *lookup_sport = 0; @@ -155,14 +157,14 @@ nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0, { case IP_PROTOCOL_ICMP: inner_icmp0 = (icmp46_header_t *) l4_header; - inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1); + inner_echo0 = (nat_icmp_echo_header_t *) (inner_icmp0 + 1); *lookup_sport = inner_echo0->identifier; *lookup_dport = inner_echo0->identifier; break; case IP_PROTOCOL_UDP: case IP_PROTOCOL_TCP: - *lookup_sport = ((tcp_udp_header_t *) l4_header)->dst_port; - *lookup_dport = ((tcp_udp_header_t *) l4_header)->src_port; + *lookup_sport = ((nat_tcp_udp_header_t *) l4_header)->dst_port; + *lookup_dport = ((nat_tcp_udp_header_t *) l4_header)->src_port; break; default: return NAT_IN2OUT_ED_ERROR_UNSUPPORTED_PROTOCOL; @@ -171,6 +173,12 @@ nat_get_icmp_session_lookup_values (vlib_buffer_t *b, ip4_header_t *ip0, return 0; } +always_inline int +nat44_ed_tcp_is_established (nat44_ed_tcp_state_e state) +{ + return state == NAT44_ED_TCP_STATE_ESTABLISHED ? 1 : 0; +} + always_inline u32 nat44_session_get_timeout (snat_main_t *sm, snat_session_t *s) { @@ -184,10 +192,10 @@ nat44_session_get_timeout (snat_main_t *sm, snat_session_t *s) return sm->timeouts.udp; case IP_PROTOCOL_TCP: { - if (s->state) - return sm->timeouts.tcp.transitory; - else + if (nat44_ed_tcp_is_established (s->tcp_state)) return sm->timeouts.tcp.established; + else + return sm->timeouts.tcp.transitory; } default: return sm->timeouts.udp; @@ -340,8 +348,7 @@ nat_lru_free_one_with_head (snat_main_t *sm, int thread_index, f64 now, sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s); - if (now >= sess_timeout_time || - (s->tcp_closed_timestamp && now >= s->tcp_closed_timestamp)) + if (now >= sess_timeout_time) { nat44_ed_free_session_data (sm, s, thread_index, 0); nat_ed_session_delete (sm, s, thread_index, 0); @@ -407,23 +414,16 @@ per_vrf_sessions_cleanup (u32 thread_index) per_vrf_sessions_t *per_vrf_sessions; u32 *to_free = 0, *i; - vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec) + pool_foreach (per_vrf_sessions, tsm->per_vrf_sessions_pool) { - if (per_vrf_sessions->expired) - { - if (per_vrf_sessions->ses_count == 0) - { - vec_add1 (to_free, per_vrf_sessions - tsm->per_vrf_sessions_vec); - } - } + if (per_vrf_sessions->expired && per_vrf_sessions->ses_count == 0) + vec_add1 (to_free, per_vrf_sessions - tsm->per_vrf_sessions_pool); } - if (vec_len (to_free)) + vec_foreach (i, to_free) { - vec_foreach (i, to_free) - { - vec_del1 (tsm->per_vrf_sessions_vec, *i); - } + per_vrf_sessions = pool_elt_at_index (tsm->per_vrf_sessions_pool, *i); + pool_put (tsm->per_vrf_sessions_pool, per_vrf_sessions); } vec_free (to_free); @@ -442,7 +442,7 @@ per_vrf_sessions_register_session (snat_session_t *s, u32 thread_index) // s->per_vrf_sessions_index == ~0 ... reuse of old session - vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec) + pool_foreach (per_vrf_sessions, tsm->per_vrf_sessions_pool) { // ignore already expired registrations if (per_vrf_sessions->expired) @@ -461,14 +461,13 @@ per_vrf_sessions_register_session (snat_session_t *s, u32 thread_index) } // create a new registration - vec_add2 (tsm->per_vrf_sessions_vec, per_vrf_sessions, 1); + pool_get (tsm->per_vrf_sessions_pool, per_vrf_sessions); clib_memset (per_vrf_sessions, 0, sizeof (*per_vrf_sessions)); - per_vrf_sessions->rx_fib_index = s->in2out.fib_index; per_vrf_sessions->tx_fib_index = s->out2in.fib_index; done: - s->per_vrf_sessions_index = per_vrf_sessions - tsm->per_vrf_sessions_vec; + s->per_vrf_sessions_index = per_vrf_sessions - tsm->per_vrf_sessions_pool; per_vrf_sessions->ses_count++; } @@ -484,7 +483,7 @@ per_vrf_sessions_unregister_session (snat_session_t *s, u32 thread_index) tsm = vec_elt_at_index (sm->per_thread_data, thread_index); per_vrf_sessions = - vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index); + pool_elt_at_index (tsm->per_vrf_sessions_pool, s->per_vrf_sessions_index); ASSERT (per_vrf_sessions->ses_count != 0); @@ -504,7 +503,7 @@ per_vrf_sessions_is_expired (snat_session_t *s, u32 thread_index) tsm = vec_elt_at_index (sm->per_thread_data, thread_index); per_vrf_sessions = - vec_elt_at_index (tsm->per_vrf_sessions_vec, s->per_vrf_sessions_index); + pool_elt_at_index (tsm->per_vrf_sessions_pool, s->per_vrf_sessions_index); return per_vrf_sessions->expired; } @@ -701,100 +700,120 @@ is_interface_addr (snat_main_t *sm, vlib_node_runtime_t *node, } always_inline void -nat44_set_tcp_session_state_i2o (snat_main_t *sm, f64 now, snat_session_t *ses, - vlib_buffer_t *b, u32 thread_index) +nat44_ed_session_reopen (u32 thread_index, snat_session_t *s) +{ + nat_syslog_nat44_sdel (0, s->in2out.fib_index, &s->in2out.addr, + s->in2out.port, &s->ext_host_nat_addr, + s->ext_host_nat_port, &s->out2in.addr, s->out2in.port, + &s->ext_host_addr, s->ext_host_port, s->proto, + nat44_ed_is_twice_nat_session (s)); + + nat_ipfix_logging_nat44_ses_delete ( + thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto, + s->in2out.port, s->out2in.port, s->in2out.fib_index); + nat_ipfix_logging_nat44_ses_create ( + thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->proto, + s->in2out.port, s->out2in.port, s->in2out.fib_index); + + nat_syslog_nat44_sadd (0, s->in2out.fib_index, &s->in2out.addr, + s->in2out.port, &s->ext_host_nat_addr, + s->ext_host_nat_port, &s->out2in.addr, s->out2in.port, + &s->ext_host_addr, s->ext_host_port, s->proto, 0); + s->total_pkts = 0; + s->total_bytes = 0; +} + +/* + * "Some rise by SYN, and some by virtue FIN" - William Shakespeare + * TCP state tracking patterned after RFC 7857 (and RFC 6146, which is + * referenced by RFC 7857). In contrast to the state machine in RFC7857 we only + * transition to ESTABLISHED state after seeing a full 3-way handshake (SYNs + * and ACKs in both directions). RFC7857 as a means of protecting against + * spurious RSTs closing a session, goes back to ESTABLISHED if a data packet + * is received after the RST. This state machine will leave the state in + * transitory if RST is seen. Our implementation also goes beyond by supporting + * creation of a new session while old session is in transitory timeout after + * seeing FIN packets from both sides. + */ +always_inline void +nat44_set_tcp_session_state (snat_main_t *sm, f64 now, snat_session_t *ses, + u8 tcp_flags, u32 thread_index, + nat44_ed_dir_e dir) { snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; - u8 tcp_flags = vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags; - u32 tcp_ack_number = vnet_buffer (b)->ip.reass.tcp_ack_number; - u32 tcp_seq_number = vnet_buffer (b)->ip.reass.tcp_seq_number; - if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST)) - ses->state = NAT44_SES_RST; - if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST)) - ses->state = 0; - if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) && - (ses->state & NAT44_SES_O2I_SYN)) - ses->state = 0; - if (tcp_flags & TCP_FLAG_SYN) - ses->state |= NAT44_SES_I2O_SYN; - 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)) + u8 old_flags = ses->tcp_flags[dir]; + ses->tcp_flags[dir] |= + tcp_flags & (TCP_FLAG_FIN | TCP_FLAG_SYN | TCP_FLAG_RST | TCP_FLAG_ACK); + if (old_flags == ses->tcp_flags[dir]) + return; + + u8 old_state = ses->tcp_state; + + switch (old_state) { - if (clib_net_to_host_u32 (tcp_ack_number) > ses->o2i_fin_seq) + case NAT44_ED_TCP_STATE_CLOSED: + // ESTABLISHED when a SYN and ACK is seen from both sides + if ((ses->tcp_flags[NAT44_ED_DIR_I2O] & + ses->tcp_flags[NAT44_ED_DIR_O2I]) == (TCP_FLAG_SYN | TCP_FLAG_ACK)) { - ses->state |= NAT44_SES_O2I_FIN_ACK; - if (nat44_is_ses_closed (ses)) - { // if session is now closed, save the timestamp - ses->tcp_closed_timestamp = now + sm->timeouts.tcp.transitory; - ses->last_lru_update = now; - } + ses->tcp_state = NAT44_ED_TCP_STATE_ESTABLISHED; + ses->lru_head_index = tsm->tcp_estab_lru_head_index; } + break; + case NAT44_ED_TCP_STATE_ESTABLISHED: + // CLOSING when a FIN is seen from either side or session has been RST + if ((ses->tcp_flags[dir] & TCP_FLAG_FIN) || + (ses->tcp_flags[dir] & TCP_FLAG_RST)) + { + ses->tcp_state = NAT44_ED_TCP_STATE_CLOSING; + ses->tcp_flags[NAT44_ED_DIR_I2O] = 0; + ses->tcp_flags[NAT44_ED_DIR_O2I] = 0; + // need to update last heard otherwise session might get + // immediately timed out if it has been idle longer than + // transitory timeout + ses->last_heard = now; + ses->lru_head_index = tsm->tcp_trans_lru_head_index; + } + break; + case NAT44_ED_TCP_STATE_CLOSING: + // Allow a transitory session to reopen + if ((ses->tcp_flags[NAT44_ED_DIR_I2O] & + ses->tcp_flags[NAT44_ED_DIR_O2I]) == (TCP_FLAG_SYN | TCP_FLAG_ACK)) + { + nat44_ed_session_reopen (thread_index, ses); + ses->tcp_state = NAT44_ED_TCP_STATE_ESTABLISHED; + ses->lru_head_index = tsm->tcp_estab_lru_head_index; + } + break; } - - // move the session to proper LRU - if (ses->state) - { - ses->lru_head_index = tsm->tcp_trans_lru_head_index; - } - else - { - ses->lru_head_index = tsm->tcp_estab_lru_head_index; - } + if (old_state == ses->tcp_state) + return; + ses->last_lru_update = now; clib_dlist_remove (tsm->lru_pool, ses->lru_index); clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index); } always_inline void +nat44_set_tcp_session_state_i2o (snat_main_t *sm, f64 now, snat_session_t *ses, + u8 tcp_flags, u32 thread_index) +{ + return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index, + NAT44_ED_DIR_I2O); +} + +always_inline void nat44_set_tcp_session_state_o2i (snat_main_t *sm, f64 now, snat_session_t *ses, - u8 tcp_flags, u32 tcp_ack_number, - u32 tcp_seq_number, u32 thread_index) + u8 tcp_flags, u32 thread_index) { - snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; - if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST)) - ses->state = NAT44_SES_RST; - if ((ses->state == NAT44_SES_RST) && !(tcp_flags & TCP_FLAG_RST)) - ses->state = 0; - if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_I2O_SYN) && - (ses->state & NAT44_SES_O2I_SYN)) - ses->state = 0; - if (tcp_flags & TCP_FLAG_SYN) - ses->state |= NAT44_SES_O2I_SYN; - 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)) - { // if session is now closed, save the timestamp - ses->tcp_closed_timestamp = now + sm->timeouts.tcp.transitory; - ses->last_lru_update = now; - } - } - // move the session to proper LRU - if (ses->state) - { - ses->lru_head_index = tsm->tcp_trans_lru_head_index; - } - else - { - ses->lru_head_index = tsm->tcp_estab_lru_head_index; - } - clib_dlist_remove (tsm->lru_pool, ses->lru_index); - clib_dlist_addtail (tsm->lru_pool, ses->lru_head_index, ses->lru_index); + return nat44_set_tcp_session_state (sm, now, ses, tcp_flags, thread_index, + NAT44_ED_DIR_O2I); } always_inline void nat44_session_update_counters (snat_session_t *s, f64 now, uword bytes, u32 thread_index) { + // regardless of TCP state, reset the timer if data packet is seen. s->last_heard = now; s->total_pkts++; s->total_bytes += bytes; diff --git a/src/plugins/nat/nat44-ed/nat44_ed_out2in.c b/src/plugins/nat/nat44-ed/nat44_ed_out2in.c index 5ad57a17098..fe4a41c5e08 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_out2in.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_out2in.c @@ -41,7 +41,6 @@ typedef enum NAT_ED_SP_REASON_NO_REASON, NAT_ED_SP_REASON_LOOKUP_FAILED, NAT_ED_SP_REASON_VRF_EXPIRED, - NAT_ED_SP_TCP_CLOSED, NAT_ED_SP_SESS_EXPIRED, } nat_slow_path_reason_e; @@ -57,6 +56,7 @@ typedef struct u8 is_slow_path; u8 translation_via_i2of; u8 lookup_skipped; + u8 tcp_state; nat_slow_path_reason_e slow_path_reason; } nat44_ed_out2in_trace_t; @@ -72,8 +72,6 @@ format_slow_path_reason (u8 *s, va_list *args) return format (s, "slow path because lookup failed"); case NAT_ED_SP_REASON_VRF_EXPIRED: return format (s, "slow path because vrf expired"); - case NAT_ED_SP_TCP_CLOSED: - return format (s, "slow path because tcp closed"); case NAT_ED_SP_SESS_EXPIRED: return format (s, "slow path because session expired"); } @@ -107,14 +105,19 @@ format_nat44_ed_out2in_trace (u8 * s, va_list * args) { if (t->lookup_skipped) { - s = format (s, "\n lookup skipped - cached session index used"); + s = format (s, "\n lookup skipped - cached session index used"); } else { s = format (s, "\n search key %U", format_ed_session_kvp, &t->search_key); } - s = format (s, "\n %U", format_slow_path_reason, t->slow_path_reason); + s = format (s, "\n %U", format_slow_path_reason, t->slow_path_reason); + } + if (IP_PROTOCOL_TCP == t->i2of.match.proto) + { + s = format (s, "\n TCP state: %U", format_nat44_ed_tcp_state, + t->tcp_state); } return s; @@ -179,7 +182,7 @@ icmp_out2in_ed_slow_path (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip, goto out; } - if (snat_static_mapping_match (vm, sm, ip->dst_address, lookup_sport, + if (snat_static_mapping_match (vm, ip->dst_address, lookup_sport, rx_fib_index, ip->protocol, &sm_addr, &sm_port, &sm_fib_index, 1, &is_addr_only, 0, 0, 0, &identity_nat, &m)) @@ -276,7 +279,8 @@ nat44_ed_alloc_i2o_port (snat_main_t *sm, snat_address_t *a, snat_session_t *s, for (int i = 0; i < ED_PORT_ALLOC_ATTEMPTS; ++i) { portnum = (sm->port_per_thread * snat_thread_index) + - snat_random_port (0, sm->port_per_thread - 1) + 1024; + snat_random_port (0, sm->port_per_thread - 1) + + ED_USER_PORT_OFFSET; portnum = clib_host_to_net_u16 (portnum); nat_6t_i2o_flow_init (sm, thread_index, s, i2o_addr, i2o_port, a->addr, portnum, i2o_fib_index, proto); @@ -645,10 +649,9 @@ create_bypass_for_fwd (snat_main_t *sm, vlib_buffer_t *b, snat_session_t *s, if (ip->protocol == IP_PROTOCOL_TCP) { - tcp_header_t *tcp = ip4_next_header (ip); - nat44_set_tcp_session_state_o2i (sm, now, s, tcp->flags, - tcp->ack_number, tcp->seq_number, - thread_index); + nat44_set_tcp_session_state_o2i ( + sm, now, s, vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags, + thread_index); } /* Accounting */ @@ -757,7 +760,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, ip_protocol_t proto0; ip4_header_t *ip0; snat_session_t *s0 = 0; - clib_bihash_kv_16_8_t kv0, value0; + clib_bihash_kv_16_8_t kv0 = {}, value0; nat_translation_error_e translation_error = NAT_ED_TRNSL_ERR_SUCCESS; nat_slow_path_reason_e slow_path_reason = NAT_ED_SP_REASON_NO_REASON; nat_6t_flow_t *f = 0; @@ -878,28 +881,12 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, // session is closed, go slow path nat44_ed_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); + s0 = 0; slow_path_reason = NAT_ED_SP_REASON_VRF_EXPIRED; next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH; goto trace0; } - if (s0->tcp_closed_timestamp) - { - if (now >= s0->tcp_closed_timestamp) - { - // session is closed, go slow path, freed in slow path - slow_path_reason = NAT_ED_SP_TCP_CLOSED; - next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH; - } - else - { - // session in transitory timeout, drop - b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TCP_CLOSED]; - next[0] = NAT_NEXT_DROP; - } - goto trace0; - } - // drop if session expired u64 sess_timeout_time; sess_timeout_time = @@ -909,6 +896,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, // session is closed, go slow path nat44_ed_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); + s0 = 0; slow_path_reason = NAT_ED_SP_SESS_EXPIRED; next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH; goto trace0; @@ -957,6 +945,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, translation_error = NAT_ED_TRNSL_ERR_FLOW_MISMATCH; nat44_ed_free_session_data (sm, s0, thread_index, 0); nat_ed_session_delete (sm, s0, thread_index, 1); + s0 = 0; next[0] = NAT_NEXT_DROP; b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TRNSL_FAILED]; goto trace0; @@ -981,10 +970,6 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, nat44_set_tcp_session_state_o2i (sm, now, s0, vnet_buffer (b0)->ip. reass.icmp_type_or_tcp_flags, - vnet_buffer (b0)->ip. - reass.tcp_ack_number, - vnet_buffer (b0)->ip. - reass.tcp_seq_number, thread_index); break; case IP_PROTOCOL_UDP: @@ -1028,6 +1013,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of)); clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if)); t->translation_via_i2of = (&s0->i2o == f); + t->tcp_state = s0->tcp_state; } else { @@ -1078,7 +1064,7 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, udp_header_t *udp0; icmp46_header_t *icmp0; snat_session_t *s0 = 0; - clib_bihash_kv_16_8_t kv0, value0; + clib_bihash_kv_16_8_t kv0 = {}, value0; lb_nat_type_t lb_nat0; twice_nat_type_t twice_nat0; u8 identity_nat0; @@ -1153,8 +1139,12 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, goto trace0; } - vlib_increment_simple_counter (&sm->counters.slowpath.out2in.icmp, - thread_index, sw_if_index0, 1); + if (NAT_NEXT_DROP != next[0]) + { + vlib_increment_simple_counter ( + &sm->counters.slowpath.out2in.icmp, thread_index, sw_if_index0, + 1); + } goto trace0; } @@ -1170,13 +1160,6 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, s0 = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value0)); - - if (s0->tcp_closed_timestamp && now >= s0->tcp_closed_timestamp) - { - nat44_ed_free_session_data (sm, s0, thread_index, 0); - nat_ed_session_delete (sm, s0, thread_index, 1); - s0 = NULL; - } } if (!s0) @@ -1185,10 +1168,9 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, destination address and port in packet */ if (snat_static_mapping_match ( - vm, sm, ip0->dst_address, - vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0, - &sm_addr, &sm_port, &sm_fib_index, 1, 0, &twice_nat0, &lb_nat0, - &ip0->src_address, &identity_nat0, &m)) + vm, ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port, + rx_fib_index0, proto0, &sm_addr, &sm_port, &sm_fib_index, 1, 0, + &twice_nat0, &lb_nat0, &ip0->src_address, &identity_nat0, &m)) { /* * Send DHCP packets to the ipv4 stack, or we won't @@ -1264,10 +1246,6 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, nat44_set_tcp_session_state_o2i (sm, now, s0, vnet_buffer (b0)->ip. reass.icmp_type_or_tcp_flags, - vnet_buffer (b0)->ip. - reass.tcp_ack_number, - vnet_buffer (b0)->ip. - reass.tcp_seq_number, thread_index); } else @@ -1300,6 +1278,7 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, t->session_index = s0 - tsm->sessions; clib_memcpy (&t->i2of, &s0->i2o, sizeof (t->i2of)); clib_memcpy (&t->o2if, &s0->o2i, sizeof (t->o2if)); + t->tcp_state = s0->tcp_state; } else { diff --git a/src/plugins/nat/nat44-ed/tcp_conn_track.rst b/src/plugins/nat/nat44-ed/tcp_conn_track.rst new file mode 100644 index 00000000000..faf0dec8b06 --- /dev/null +++ b/src/plugins/nat/nat44-ed/tcp_conn_track.rst @@ -0,0 +1,65 @@ +NAT44ED TCP connection tracking +=============================== + +TCP connection tracking in endpoint-dependent NAT is based on RFC 7857 +and RFC 6146, which RFC 7857 references. + +See RFC 7857 for the original graph - our graph is slightly different, +allowing creation of new session, while an old session is in transitory +timeout after seeing FIN packets from both sides: + +After discussion on vpp-dev and with Andrew Yourtschenko we agreed that +it's friendly behaviour to allow creating a new session while the old +one is closed and in transitory timeout. The alternative means VPP is +insisting that a 5-tuple connection cannot be created while an old one +is finished and timing out. There is no apparent reason why our change +would break anything and we agreed that it could only help users. + +:: + + + +------------transitory timeout----------------+ + | | + | +-------------+ | + | session created---->+ CLOSED | | + | +-------------+ | + | | | | ++-----+ | SYN SYN | +| v v IN2OUT OUT2IN | +| +->session removed | | | +| | ^ ^ ^ ^ ^ v v | +| | | | | | | +-------+ +-------+ | +| | | | | | +----transitory timeout---+SYN_I2O| |SYN_O2I+--+ +| | | | | | +---------+ |-------| |-------| +| | | | | +-transitory---+RST_TRANS| | | +| | | | | timeout +---------+ SYN SYN +| | | | | | ^ OUT2IN IN2OUT +| | | | | | | | | +| | | | | | | v v +| | | | | | | +-----------+ +| | | | | | +--RST----+ESTABLISHED+<-SYN IN2OUT-+ +| | | | | | +-----------+ | +| | | | | +---data pkt-----^ | | | ^ | +| | | | | | | | | | +| | | | +----established timeout---------------+ | | | | +| | | | | | | | +| | | | +-----FIN IN2OUT---------+ | | | +| | | | v | | | +| | | | +-------+ +--FIN OUT2IN----+ | | +| | | +--established---+FIN_I2O| | | | +| | | timeout +-------+ v +-SYN OUT2IN-+ | +| | | | +-------+ | | +| | +----established-------------+FIN_O2I| +--------------+ | +| | timeout | +-------+ |REOPEN_SYN_I2O| +--------------+ +| | | | +--------------+ |REOPEN_SYN_O2I| +| | FIN FIN ^ | +--------------+ +| | OUT2IN IN2OUT | | ^ | +| | | | | | | | +| | v v | | | | +| | +-------------+ | | | | +| +--transitory timeout---+ FIN_TRANS +-SYN IN2OUT-+ | | | +| +-------------+ | | | +| | | | | +| +--------SYN OUT2IN----|-----------+ | +| v | ++------------------transitory timeout-------------------+<-------------+ diff --git a/src/plugins/nat/nat44-ei/nat44_ei.api b/src/plugins/nat/nat44-ei/nat44_ei.api index e535906321a..6d24b541e8d 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei.api +++ b/src/plugins/nat/nat44-ei/nat44_ei.api @@ -823,6 +823,52 @@ define nat44_ei_user_session_details { u16 ext_host_port; }; +/** \brief NAT44 user's sessions + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param ip_address - IPv4 address of the user to dump + @param vrf_id - VRF_ID +*/ +define nat44_ei_user_session_v2_dump { + option in_progress; + u32 client_index; + u32 context; + vl_api_ip4_address_t ip_address; + u32 vrf_id; +}; + +/** \brief NAT44 user's sessions response + @param context - sender context, to match reply w/ request + @param outside_ip_address - outside IPv4 address + @param outside_port - outside port + @param inside_ip_address - inside IPv4 address + @param inside_port - inside port + @param protocol - protocol + @param flags - flag NAT_IS_STATIC if session is static + @param last_heard - last heard timer since VPP start + @param time_since_last_heard - difference between current vpp time and last_heard value + @param total_bytes - count of bytes sent through session + @param total_pkts - count of pakets sent through session + @param ext_host_address - external host IPv4 address + @param ext_host_port - external host port +*/ +define nat44_ei_user_session_v2_details { + option in_progress; + u32 context; + vl_api_ip4_address_t outside_ip_address; + u16 outside_port; + vl_api_ip4_address_t inside_ip_address; + u16 inside_port; + u16 protocol; + vl_api_nat44_ei_config_flags_t flags; + u64 last_heard; + u64 time_since_last_heard; + u64 total_bytes; + u32 total_pkts; + vl_api_ip4_address_t ext_host_address; + u16 ext_host_port; +}; + /** \brief Delete NAT44 session @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/plugins/nat/nat44-ei/nat44_ei.c b/src/plugins/nat/nat44-ei/nat44_ei.c index 694bc6bec5a..e16625a2946 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei.c +++ b/src/plugins/nat/nat44-ei/nat44_ei.c @@ -40,7 +40,6 @@ nat44_ei_main_t nat44_ei_main; extern vlib_node_registration_t nat44_ei_hairpinning_node; -extern vlib_node_registration_t nat44_ei_hairpin_dst_node; extern vlib_node_registration_t nat44_ei_in2out_hairpinning_finish_ip4_lookup_node; extern vlib_node_registration_t @@ -62,7 +61,7 @@ extern vlib_node_registration_t if (PREDICT_FALSE (nm->enabled)) \ { \ nat44_ei_log_err ("plugin enabled"); \ - return 1; \ + return VNET_API_ERROR_FEATURE_ALREADY_ENABLED; \ } \ } \ while (0) @@ -74,7 +73,7 @@ extern vlib_node_registration_t if (PREDICT_FALSE (!nm->enabled)) \ { \ nat44_ei_log_err ("plugin disabled"); \ - return 1; \ + return VNET_API_ERROR_FEATURE_ALREADY_DISABLED; \ } \ } \ while (0) @@ -111,31 +110,6 @@ VNET_FEATURE_INIT (ip4_nat44_ei_in2out_output, static) = { .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa", "ip4-sv-reassembly-output-feature"), }; -VNET_FEATURE_INIT (ip4_nat44_ei_in2out_fast, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-ei-in2out-fast", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa", - "ip4-sv-reassembly-feature"), -}; -VNET_FEATURE_INIT (ip4_nat44_ei_out2in_fast, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-ei-out2in-fast", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa", - "ip4-sv-reassembly-feature", - "ip4-dhcp-client-detect"), -}; -VNET_FEATURE_INIT (ip4_nat44_ei_hairpin_dst, static) = { - .arc_name = "ip4-unicast", - .node_name = "nat44-ei-hairpin-dst", - .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa", - "ip4-sv-reassembly-feature"), -}; -VNET_FEATURE_INIT (ip4_nat44_ei_hairpin_src, static) = { - .arc_name = "ip4-output", - .node_name = "nat44-ei-hairpin-src", - .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa", - "ip4-sv-reassembly-output-feature"), -}; VNET_FEATURE_INIT (ip4_nat44_ei_hairpinning, static) = { .arc_name = "ip4-local", .node_name = "nat44-ei-hairpinning", @@ -200,6 +174,39 @@ typedef struct void nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index, int is_add); +static void nat44_ei_worker_db_free (nat44_ei_main_per_thread_data_t *tnm); + +static int nat44_ei_add_static_mapping_internal ( + ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, + nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags, + ip4_address_t pool_addr, u8 *tag); + +static int nat44_ei_del_static_mapping_internal ( + ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, + nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags); + +always_inline bool +nat44_ei_port_is_used (nat44_ei_address_t *a, u8 proto, u16 port) +{ + return clib_bitmap_get (a->busy_port_bitmap[proto], port); +} + +always_inline void +nat44_ei_port_get (nat44_ei_address_t *a, u8 proto, u16 port) +{ + ASSERT (!nat44_ei_port_is_used (a, proto, port)); + a->busy_port_bitmap[proto] = + clib_bitmap_set (a->busy_port_bitmap[proto], port, 1); +} + +always_inline void +nat44_ei_port_put (nat44_ei_address_t *a, u8 proto, u16 port) +{ + ASSERT (nat44_ei_port_is_used (a, proto, port)); + a->busy_port_bitmap[proto] = + clib_bitmap_set (a->busy_port_bitmap[proto], port, 0); +} + static u8 * format_nat44_ei_classify_trace (u8 *s, va_list *args) { @@ -219,8 +226,6 @@ format_nat44_ei_classify_trace (u8 *s, va_list *args) return s; } -static void nat44_ei_db_free (); - static void nat44_ei_db_init (u32 translations, u32 translation_buckets, u32 user_buckets); @@ -473,8 +478,6 @@ nat44_ei_init (vlib_main_t *vm) nm->hairpinning_fq_index = vlib_frame_queue_main_init (nat44_ei_hairpinning_node.index, 0); - nm->hairpin_dst_fq_index = - vlib_frame_queue_main_init (nat44_ei_hairpin_dst_node.index, 0); nm->in2out_hairpinning_finish_ip4_lookup_node_fq_index = vlib_frame_queue_main_init ( nat44_ei_in2out_hairpinning_finish_ip4_lookup_node.index, 0); @@ -537,8 +540,6 @@ nat44_ei_plugin_enable (nat44_ei_config_t c) nm->user_buckets); nat44_ei_set_alloc_default (); - // TODO: zero simple counter for all counters missing - vlib_zero_simple_counter (&nm->total_users, 0); vlib_zero_simple_counter (&nm->total_sessions, 0); vlib_zero_simple_counter (&nm->user_limit_reached, 0); @@ -568,20 +569,6 @@ nat44_ei_plugin_enable (nat44_ei_config_t c) return 0; } -void -nat44_ei_addresses_free (nat44_ei_address_t **addresses) -{ - nat44_ei_address_t *ap; - vec_foreach (ap, *addresses) - { -#define _(N, i, n, s) vec_free (ap->busy_##n##_ports_per_thread); - foreach_nat_protocol -#undef _ - } - vec_free (*addresses); - *addresses = 0; -} - static_always_inline nat44_ei_outside_fib_t * nat44_ei_get_outside_fib (nat44_ei_outside_fib_t *outside_fibs, u32 fib_index) { @@ -611,6 +598,37 @@ nat44_ei_get_interface (nat44_ei_interface_t *interfaces, u32 sw_if_index) } static_always_inline int +nat44_ei_hairpinning_enable (u8 is_enable) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + u32 sw_if_index = 0; // local0 + + if (is_enable) + { + nm->hairpin_reg += 1; + if (1 == nm->hairpin_reg) + { + return vnet_feature_enable_disable ( + "ip4-local", "nat44-ei-hairpinning", sw_if_index, is_enable, 0, 0); + } + } + else + { + if (0 == nm->hairpin_reg) + return 1; + + nm->hairpin_reg -= 1; + if (0 == nm->hairpin_reg) + { + return vnet_feature_enable_disable ( + "ip4-local", "nat44-ei-hairpinning", sw_if_index, is_enable, 0, 0); + } + } + + return 0; +} + +int nat44_ei_add_interface (u32 sw_if_index, u8 is_inside) { const char *feature_name, *del_feature_name; @@ -676,8 +694,7 @@ nat44_ei_add_interface (u32 sw_if_index, u8 is_inside) } if (!is_inside) { - rv = vnet_feature_enable_disable ( - "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0); + rv = nat44_ei_hairpinning_enable (0); if (rv) { return rv; @@ -710,8 +727,7 @@ nat44_ei_add_interface (u32 sw_if_index, u8 is_inside) } if (is_inside && !nm->out2in_dpo) { - rv = vnet_feature_enable_disable ( - "ip4-local", "nat44-ei-hairpinning", sw_if_index, 1, 0, 0); + rv = nat44_ei_hairpinning_enable (1); if (rv) { return rv; @@ -753,7 +769,7 @@ nat44_ei_add_interface (u32 sw_if_index, u8 is_inside) return 0; } -static_always_inline int +int nat44_ei_del_interface (u32 sw_if_index, u8 is_inside) { const char *feature_name, *del_feature_name; @@ -816,8 +832,7 @@ nat44_ei_del_interface (u32 sw_if_index, u8 is_inside) } else { - rv = vnet_feature_enable_disable ( - "ip4-local", "nat44-ei-hairpinning", sw_if_index, 1, 0, 0); + rv = nat44_ei_hairpinning_enable (1); if (rv) { return rv; @@ -850,8 +865,7 @@ nat44_ei_del_interface (u32 sw_if_index, u8 is_inside) } if (is_inside) { - rv = vnet_feature_enable_disable ( - "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0); + rv = nat44_ei_hairpinning_enable (0); if (rv) { return rv; @@ -884,19 +898,6 @@ nat44_ei_del_interface (u32 sw_if_index, u8 is_inside) } int -nat44_ei_add_del_interface (u32 sw_if_index, u8 is_inside, int is_del) -{ - if (is_del) - { - return nat44_ei_del_interface (sw_if_index, is_inside); - } - else - { - return nat44_ei_add_interface (sw_if_index, is_inside); - } -} - -static_always_inline int nat44_ei_add_output_interface (u32 sw_if_index) { nat44_ei_main_t *nm = &nat44_ei_main; @@ -1000,7 +1001,7 @@ nat44_ei_add_output_interface (u32 sw_if_index) return 0; } -static_always_inline int +int nat44_ei_del_output_interface (u32 sw_if_index) { nat44_ei_main_t *nm = &nat44_ei_main; @@ -1085,8 +1086,8 @@ nat44_ei_del_output_interface (u32 sw_if_index) } } - nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 1); - nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1); + nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 0); + nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 0); return 0; } @@ -1105,13 +1106,38 @@ nat44_ei_add_del_output_interface (u32 sw_if_index, int is_del) } int -nat44_ei_plugin_disable () +nat44_ei_del_addresses () +{ + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_address_t *a, *vec; + int error = 0; + + vec = vec_dup (nm->addresses); + vec_foreach (a, vec) + { + error = nat44_ei_del_address (a->addr, 0); + + if (error) + { + nat44_ei_log_err ("error occurred while removing adderess"); + } + } + vec_free (vec); + vec_free (nm->addresses); + nm->addresses = 0; + + vec_free (nm->auto_add_sw_if_indices); + nm->auto_add_sw_if_indices = 0; + return error; +} + +int +nat44_ei_del_interfaces () { nat44_ei_main_t *nm = &nat44_ei_main; nat44_ei_interface_t *i, *pool; int error = 0; - // first unregister all nodes from interfaces pool = pool_dup (nm->interfaces); pool_foreach (i, pool) { @@ -1126,12 +1152,21 @@ nat44_ei_plugin_disable () if (error) { - nat44_ei_log_err ("error occurred while removing interface %u", - i->sw_if_index); + nat44_ei_log_err ("error occurred while removing interface"); } } pool_free (pool); pool_free (nm->interfaces); + nm->interfaces = 0; + return error; +} + +int +nat44_ei_del_output_interfaces () +{ + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_interface_t *i, *pool; + int error = 0; pool = pool_dup (nm->output_feature_interfaces); pool_foreach (i, pool) @@ -1139,30 +1174,139 @@ nat44_ei_plugin_disable () error = nat44_ei_del_output_interface (i->sw_if_index); if (error) { - nat44_ei_log_err ("error occurred while removing interface %u", - i->sw_if_index); + nat44_ei_log_err ("error occurred while removing output interface"); } } pool_free (pool); pool_free (nm->output_feature_interfaces); + nm->output_feature_interfaces = 0; + return error; +} - nat_ha_disable (); - nat44_ei_db_free (); +static clib_error_t * +nat44_ei_sw_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_interface_t *i; + int error = 0; - nat44_ei_addresses_free (&nm->addresses); + if (is_add) + return 0; - vec_free (nm->to_resolve); - vec_free (nm->auto_add_sw_if_indices); + if (!nm->enabled) + return 0; + + i = nat44_ei_get_interface (nm->interfaces, sw_if_index); + if (i) + { + bool is_inside = nat44_ei_interface_is_inside (i); + bool is_outside = nat44_ei_interface_is_outside (i); + + if (is_inside) + { + error |= nat44_ei_del_interface (sw_if_index, 1); + } + if (is_outside) + { + error |= nat44_ei_del_interface (sw_if_index, 0); + } + + if (error) + { + nat44_ei_log_err ("error occurred while removing interface"); + } + } + + i = nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index); + if (i) + { + error = nat44_ei_del_output_interface (sw_if_index); + if (error) + { + nat44_ei_log_err ("error occurred while removing output interface"); + } + } + + return 0; +} + +VNET_SW_INTERFACE_ADD_DEL_FUNCTION (nat44_ei_sw_interface_add_del); + +int +nat44_ei_del_static_mappings () +{ + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_static_mapping_t *m, *pool; + int error = 0; + + pool = pool_dup (nm->static_mappings); + pool_foreach (m, pool) + { + error = nat44_ei_del_static_mapping_internal ( + m->local_addr, m->external_addr, m->local_port, m->external_port, + m->proto, m->vrf_id, ~0, m->flags); + if (error) + { + nat44_ei_log_err ("error occurred while removing mapping"); + } + } + pool_free (pool); + pool_free (nm->static_mappings); + nm->static_mappings = 0; + vec_free (nm->to_resolve); nm->to_resolve = 0; - nm->auto_add_sw_if_indices = 0; - nm->forwarding_enabled = 0; + clib_bihash_free_8_8 (&nm->static_mapping_by_local); + clib_bihash_free_8_8 (&nm->static_mapping_by_external); + + return error; +} + +int +nat44_ei_plugin_disable () +{ + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_main_per_thread_data_t *tnm; + int rc, error = 0; + + fail_if_disabled (); + + nat_ha_disable (); + + rc = nat44_ei_del_static_mappings (); + if (rc) + error = VNET_API_ERROR_BUG; + + rc = nat44_ei_del_addresses (); + if (rc) + error = VNET_API_ERROR_BUG; + + rc = nat44_ei_del_interfaces (); + if (rc) + error = VNET_API_ERROR_BUG; + + rc = nat44_ei_del_output_interfaces (); + if (rc) + error = VNET_API_ERROR_BUG; + + if (nm->pat) + { + clib_bihash_free_8_8 (&nm->in2out); + clib_bihash_free_8_8 (&nm->out2in); + + vec_foreach (tnm, nm->per_thread_data) + { + nat44_ei_worker_db_free (tnm); + } + } - nm->enabled = 0; clib_memset (&nm->rconfig, 0, sizeof (nm->rconfig)); - return 0; + nm->forwarding_enabled = 0; + nm->enabled = 0; + + return error; } int @@ -1170,7 +1314,6 @@ nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses, u32 thread_index, ip4_address_t addr, u16 port, nat_protocol_t protocol) { - nat44_ei_main_t *nm = &nat44_ei_main; nat44_ei_address_t *a = 0; u32 address_index; u16 port_host_byte_order = clib_net_to_host_u16 (port); @@ -1181,21 +1324,13 @@ nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses, continue; a = addresses + address_index; - switch (protocol) - { -#define _(N, j, n, s) \ - case NAT_PROTOCOL_##N: \ - if (a->busy_##n##_port_refcounts[port_host_byte_order]) \ - return VNET_API_ERROR_INSTANCE_IN_USE; \ - ++a->busy_##n##_port_refcounts[port_host_byte_order]; \ - a->busy_##n##_ports_per_thread[thread_index]++; \ - a->busy_##n##_ports++; \ - return 0; - foreach_nat_protocol -#undef _ - default : nat_elog_info (nm, "unknown protocol"); - return 1; - } + if (nat44_ei_port_is_used (a, protocol, port_host_byte_order)) + return VNET_API_ERROR_INSTANCE_IN_USE; + + nat44_ei_port_get (a, protocol, port_host_byte_order); + a->busy_ports_per_thread[protocol][thread_index]++; + a->busy_ports[protocol]++; + return 0; } return VNET_API_ERROR_NO_SUCH_ENTRY; @@ -1230,7 +1365,6 @@ nat44_ei_free_outside_address_and_port (nat44_ei_address_t *addresses, u32 thread_index, ip4_address_t *addr, u16 port, nat_protocol_t protocol) { - nat44_ei_main_t *nm = &nat44_ei_main; nat44_ei_address_t *a; u32 address_index; u16 port_host_byte_order = clib_net_to_host_u16 (port); @@ -1244,21 +1378,9 @@ nat44_ei_free_outside_address_and_port (nat44_ei_address_t *addresses, ASSERT (address_index < vec_len (addresses)); a = addresses + address_index; - - switch (protocol) - { -#define _(N, i, n, s) \ - case NAT_PROTOCOL_##N: \ - ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \ - --a->busy_##n##_port_refcounts[port_host_byte_order]; \ - a->busy_##n##_ports--; \ - a->busy_##n##_ports_per_thread[thread_index]--; \ - break; - foreach_nat_protocol -#undef _ - default : nat_elog_info (nm, "unknown protocol"); - return; - } + nat44_ei_port_put (a, protocol, port_host_byte_order); + a->busy_ports[protocol]--; + a->busy_ports_per_thread[protocol][thread_index]--; } void @@ -1613,6 +1735,20 @@ nat44_ei_get_in2out_worker_index (ip4_header_t *ip0, u32 rx_fib_index0, } u32 +nat44_ei_get_thread_idx_by_port (u16 e_port) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + u32 thread_idx = nm->num_workers; + if (nm->num_workers > 1) + { + thread_idx = nm->first_worker_index + + nm->workers[(e_port - 1024) / nm->port_per_thread % + _vec_len (nm->workers)]; + } + return thread_idx; +} + +u32 nat44_ei_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip0, u32 rx_fib_index0, u8 is_output) { @@ -1690,9 +1826,8 @@ nat44_ei_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip0, } /* worker by outside port */ - next_worker_index = nm->first_worker_index; - next_worker_index += - nm->workers[(clib_net_to_host_u16 (port) - 1024) / nm->port_per_thread]; + next_worker_index = + nat44_ei_get_thread_idx_by_port (clib_net_to_host_u16 (port)); return next_worker_index; } @@ -1710,75 +1845,95 @@ nat44_ei_alloc_default_cb (nat44_ei_address_t *addresses, u32 fib_index, if (vec_len (addresses) > 0) { - int s_addr_offset = s_addr.as_u32 % vec_len (addresses); for (i = s_addr_offset; i < vec_len (addresses); ++i) { a = addresses + i; - switch (proto) + + if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread) { -#define _(N, j, n, s) \ - case NAT_PROTOCOL_##N: \ - if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \ - { \ - if (a->fib_index == fib_index) \ - { \ - while (1) \ - { \ - portnum = (port_per_thread * snat_thread_index) + \ - nat_random_port (&nm->random_seed, 0, \ - port_per_thread - 1) + \ - 1024; \ - if (a->busy_##n##_port_refcounts[portnum]) \ - continue; \ - --a->busy_##n##_port_refcounts[portnum]; \ - a->busy_##n##_ports_per_thread[thread_index]++; \ - a->busy_##n##_ports++; \ - *addr = a->addr; \ - *port = clib_host_to_net_u16 (portnum); \ - return 0; \ - } \ - } \ - else if (a->fib_index == ~0) \ - { \ - ga = a; \ - } \ - } \ - break; - foreach_nat_protocol; - default: - nat_elog_info (nm, "unknown protocol"); - return 1; + if (a->fib_index == fib_index) + { + while (1) + { + portnum = (port_per_thread * snat_thread_index) + + nat_random_port (&nm->random_seed, 0, + port_per_thread - 1) + + 1024; + if (nat44_ei_port_is_used (a, proto, portnum)) + continue; + nat44_ei_port_get (a, proto, portnum); + a->busy_ports_per_thread[proto][thread_index]++; + a->busy_ports[proto]++; + *addr = a->addr; + *port = clib_host_to_net_u16 (portnum); + return 0; + } + } + else if (a->fib_index == ~0) + { + ga = a; + } } } for (i = 0; i < s_addr_offset; ++i) { a = addresses + i; - switch (proto) + if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread) { - foreach_nat_protocol; - default: - nat_elog_info (nm, "unknown protocol"); - return 1; + if (a->fib_index == fib_index) + { + while (1) + { + portnum = (port_per_thread * snat_thread_index) + + nat_random_port (&nm->random_seed, 0, + port_per_thread - 1) + + 1024; + if (nat44_ei_port_is_used (a, proto, portnum)) + continue; + nat44_ei_port_get (a, proto, portnum); + a->busy_ports_per_thread[proto][thread_index]++; + a->busy_ports[proto]++; + *addr = a->addr; + *port = clib_host_to_net_u16 (portnum); + return 0; + } + } + else if (a->fib_index == ~0) + { + ga = a; + } } } - if (ga) - { - a = ga; - // fake fib index to reuse macro - fib_index = ~0; - switch (proto) + + if (ga) { - foreach_nat_protocol; - default : nat_elog_info (nm, "unknown protocol"); - return 1; + a = ga; + if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread) + { + if (a->fib_index == ~0) + { + while (1) + { + portnum = (port_per_thread * snat_thread_index) + + nat_random_port (&nm->random_seed, 0, + port_per_thread - 1) + + 1024; + if (nat44_ei_port_is_used (a, proto, portnum)) + continue; + nat44_ei_port_get (a, proto, portnum); + a->busy_ports_per_thread[proto][thread_index]++; + a->busy_ports[proto]++; + *addr = a->addr; + *port = clib_host_to_net_u16 (portnum); + return 0; + } + } + } } } - } - -#undef _ /* Totally out of translations to use... */ nat_ipfix_logging_addresses_exhausted (thread_index, 0); @@ -1800,30 +1955,20 @@ nat44_ei_alloc_range_cb (nat44_ei_address_t *addresses, u32 fib_index, if (!vec_len (addresses)) goto exhausted; - switch (proto) - { -#define _(N, i, n, s) \ - case NAT_PROTOCOL_##N: \ - if (a->busy_##n##_ports < ports) \ - { \ - while (1) \ - { \ - portnum = nat_random_port (&nm->random_seed, nm->start_port, \ - nm->end_port); \ - if (a->busy_##n##_port_refcounts[portnum]) \ - continue; \ - ++a->busy_##n##_port_refcounts[portnum]; \ - a->busy_##n##_ports++; \ - *addr = a->addr; \ - *port = clib_host_to_net_u16 (portnum); \ - return 0; \ - } \ - } \ - break; - foreach_nat_protocol -#undef _ - default : nat_elog_info (nm, "unknown protocol"); - return 1; + if (a->busy_ports[proto] < ports) + { + while (1) + { + portnum = + nat_random_port (&nm->random_seed, nm->start_port, nm->end_port); + if (nat44_ei_port_is_used (a, proto, portnum)) + continue; + nat44_ei_port_get (a, proto, portnum); + a->busy_ports[proto]++; + *addr = a->addr; + *port = clib_host_to_net_u16 (portnum); + return 0; + } } exhausted: @@ -1847,32 +1992,22 @@ nat44_ei_alloc_mape_cb (nat44_ei_address_t *addresses, u32 fib_index, if (!vec_len (addresses)) goto exhausted; - switch (proto) - { -#define _(N, i, n, s) \ - case NAT_PROTOCOL_##N: \ - if (a->busy_##n##_ports < ports) \ - { \ - while (1) \ - { \ - A = nat_random_port (&nm->random_seed, 1, \ - pow2_mask (nm->psid_offset)); \ - j = nat_random_port (&nm->random_seed, 0, pow2_mask (m)); \ - portnum = A | (nm->psid << nm->psid_offset) | (j << (16 - m)); \ - if (a->busy_##n##_port_refcounts[portnum]) \ - continue; \ - ++a->busy_##n##_port_refcounts[portnum]; \ - a->busy_##n##_ports++; \ - *addr = a->addr; \ - *port = clib_host_to_net_u16 (portnum); \ - return 0; \ - } \ - } \ - break; - foreach_nat_protocol -#undef _ - default : nat_elog_info (nm, "unknown protocol"); - return 1; + if (a->busy_ports[proto] < ports) + { + while (1) + { + A = + nat_random_port (&nm->random_seed, 1, pow2_mask (nm->psid_offset)); + j = nat_random_port (&nm->random_seed, 0, pow2_mask (m)); + portnum = A | (nm->psid << nm->psid_offset) | (j << (16 - m)); + if (nat44_ei_port_is_used (a, proto, portnum)) + continue; + nat44_ei_port_get (a, proto, portnum); + a->busy_ports[proto]++; + *addr = a->addr; + *port = clib_host_to_net_u16 (portnum); + return 0; + } } exhausted: @@ -1979,19 +2114,6 @@ nat44_ei_del_session (nat44_ei_main_t *nm, ip4_address_t *addr, u16 port, return VNET_API_ERROR_NO_SUCH_ENTRY; } -u32 -nat44_ei_get_thread_idx_by_port (u16 e_port) -{ - nat44_ei_main_t *nm = &nat44_ei_main; - u32 thread_idx = nm->num_workers; - if (nm->num_workers > 1) - { - thread_idx = nm->first_worker_index + - nm->workers[(e_port - 1024) / nm->port_per_thread]; - } - return thread_idx; -} - void nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index, int is_add) @@ -2036,29 +2158,18 @@ nat44_ei_reserve_port (ip4_address_t addr, u16 port, nat_protocol_t proto) if (a->addr.as_u32 != addr.as_u32) continue; - switch (proto) - { -#define _(N, j, n, s) \ - case NAT_PROTOCOL_##N: \ - if (a->busy_##n##_port_refcounts[port]) \ - goto done; \ - ++a->busy_##n##_port_refcounts[port]; \ - if (port > 1024) \ - { \ - a->busy_##n##_ports++; \ - a->busy_##n##_ports_per_thread[ti]++; \ - } \ - break; - foreach_nat_protocol -#undef _ - default : nat_elog_info (nm, "unknown protocol"); - goto done; - } + if (nat44_ei_port_is_used (a, proto, port)) + continue; + nat44_ei_port_get (a, proto, port); + if (port > 1024) + { + a->busy_ports[proto]++; + a->busy_ports_per_thread[proto][ti]++; + } return 0; } -done: return 1; } @@ -2077,27 +2188,15 @@ nat44_ei_free_port (ip4_address_t addr, u16 port, nat_protocol_t proto) if (a->addr.as_u32 != addr.as_u32) continue; - switch (proto) - { -#define _(N, j, n, s) \ - case NAT_PROTOCOL_##N: \ - --a->busy_##n##_port_refcounts[port]; \ - if (port > 1024) \ - { \ - a->busy_##n##_ports--; \ - a->busy_##n##_ports_per_thread[ti]--; \ - } \ - break; - foreach_nat_protocol -#undef _ - default : nat_elog_info (nm, "unknown protocol"); - goto done; + nat44_ei_port_put (a, proto, port); + if (port > 1024) + { + a->busy_ports[proto]--; + a->busy_ports_per_thread[proto][ti]--; } - return 0; } -done: return 1; } @@ -2250,37 +2349,54 @@ nat44_ei_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port, nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags, ip4_address_t pool_addr, u8 *tag) + { nat44_ei_main_t *nm = &nat44_ei_main; - clib_bihash_kv_8_8_t kv, value; - nat44_ei_lb_addr_port_t *local; - nat44_ei_static_mapping_t *m; - u32 fib_index = ~0; - u32 worker_index; - - fail_if_disabled (); - - if (is_sm_addr_only (flags)) - { - e_port = l_port = proto = 0; - } - if (sw_if_index != ~0) + if (is_sm_switch_address (flags)) { - // this mapping is interface bound - ip4_address_t *first_int_addr; - - // check if this record isn't registered for resolve if (!nat44_ei_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id, sw_if_index, flags, 0)) { return VNET_API_ERROR_VALUE_EXIST; } - // register record for resolve + nat44_ei_add_resolve_record (l_addr, l_port, e_port, proto, vrf_id, sw_if_index, flags, pool_addr, tag); - first_int_addr = + ip4_address_t *first_int_addr = + ip4_interface_first_address (nm->ip4_main, sw_if_index, 0); + if (!first_int_addr) + { + // dhcp resolution required + return 0; + } + + e_addr.as_u32 = first_int_addr->as_u32; + } + + return nat44_ei_add_static_mapping_internal (l_addr, e_addr, l_port, e_port, + proto, vrf_id, sw_if_index, + flags, pool_addr, tag); +} + +int +nat44_ei_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, + u16 l_port, u16 e_port, nat_protocol_t proto, + u32 vrf_id, u32 sw_if_index, u32 flags) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + + if (is_sm_switch_address (flags)) + { + + if (nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id, + sw_if_index, flags)) + { + return VNET_API_ERROR_NO_SUCH_ENTRY; + } + + ip4_address_t *first_int_addr = ip4_interface_first_address (nm->ip4_main, sw_if_index, 0); if (!first_int_addr) { @@ -2291,6 +2407,31 @@ nat44_ei_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, e_addr.as_u32 = first_int_addr->as_u32; } + return nat44_ei_del_static_mapping_internal ( + l_addr, e_addr, l_port, e_port, proto, vrf_id, sw_if_index, flags); +} + +static int +nat44_ei_add_static_mapping_internal (ip4_address_t l_addr, + ip4_address_t e_addr, u16 l_port, + u16 e_port, nat_protocol_t proto, + u32 vrf_id, u32 sw_if_index, u32 flags, + ip4_address_t pool_addr, u8 *tag) +{ + nat44_ei_main_t *nm = &nat44_ei_main; + clib_bihash_kv_8_8_t kv, value; + nat44_ei_lb_addr_port_t *local; + nat44_ei_static_mapping_t *m; + u32 fib_index = ~0; + u32 worker_index; + + fail_if_disabled (); + + if (is_sm_addr_only (flags)) + { + e_port = l_port = proto = 0; + } + if (is_sm_identity_nat (flags)) { l_port = e_port; @@ -2358,7 +2499,7 @@ nat44_ei_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, if (nat44_ei_reserve_port (e_addr, e_port, proto)) { // remove resolve record - if ((sw_if_index != ~0) && !is_sm_identity_nat (flags)) + if ((is_sm_switch_address (flags)) && !is_sm_identity_nat (flags)) { nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id, sw_if_index, flags); @@ -2427,10 +2568,11 @@ nat44_ei_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, return 0; } -int -nat44_ei_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, - u16 l_port, u16 e_port, nat_protocol_t proto, - u32 vrf_id, u32 sw_if_index, u32 flags) +static int +nat44_ei_del_static_mapping_internal (ip4_address_t l_addr, + ip4_address_t e_addr, u16 l_port, + u16 e_port, nat_protocol_t proto, + u32 vrf_id, u32 sw_if_index, u32 flags) { nat44_ei_main_per_thread_data_t *tnm; nat44_ei_main_t *nm = &nat44_ei_main; @@ -2447,29 +2589,6 @@ nat44_ei_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, e_port = l_port = proto = 0; } - if (sw_if_index != ~0) - { - // this mapping is interface bound - ip4_address_t *first_int_addr; - - // delete record registered for resolve - if (nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id, - sw_if_index, flags)) - { - return VNET_API_ERROR_NO_SUCH_ENTRY; - } - - first_int_addr = - ip4_interface_first_address (nm->ip4_main, sw_if_index, 0); - if (!first_int_addr) - { - // dhcp resolution required - return 0; - } - - e_addr.as_u32 = first_int_addr->as_u32; - } - if (is_sm_identity_nat (flags)) { l_port = e_port; @@ -2481,7 +2600,7 @@ nat44_ei_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr, if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value)) { - if (sw_if_index != ~0) + if (is_sm_switch_address (flags)) { return 0; } @@ -2736,27 +2855,6 @@ nat44_ei_worker_db_init (nat44_ei_main_per_thread_data_t *tnm, } static void -nat44_ei_db_free () -{ - nat44_ei_main_t *nm = &nat44_ei_main; - nat44_ei_main_per_thread_data_t *tnm; - - pool_free (nm->static_mappings); - clib_bihash_free_8_8 (&nm->static_mapping_by_local); - clib_bihash_free_8_8 (&nm->static_mapping_by_external); - - if (nm->pat) - { - clib_bihash_free_8_8 (&nm->in2out); - clib_bihash_free_8_8 (&nm->out2in); - vec_foreach (tnm, nm->per_thread_data) - { - nat44_ei_worker_db_free (tnm); - } - } -} - -static void nat44_ei_db_init (u32 translations, u32 translation_buckets, u32 user_buckets) { nat44_ei_main_t *nm = &nat44_ei_main; @@ -2919,15 +3017,15 @@ nat44_ei_add_address (ip4_address_t *addr, u32 vrf_id) FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low); } -#define _(N, i, n, s) \ - clib_memset (ap->busy_##n##_port_refcounts, 0, \ - sizeof (ap->busy_##n##_port_refcounts)); \ - ap->busy_##n##_ports = 0; \ - ap->busy_##n##_ports_per_thread = 0; \ - vec_validate_init_empty (ap->busy_##n##_ports_per_thread, \ - tm->n_vlib_mains - 1, 0); - foreach_nat_protocol -#undef _ + nat_protocol_t proto; + for (proto = 0; proto < NAT_N_PROTOCOLS; ++proto) + { + ap->busy_port_bitmap[proto] = 0; + ap->busy_ports[proto] = 0; + ap->busy_ports_per_thread[proto] = 0; + vec_validate_init_empty (ap->busy_ports_per_thread[proto], + tm->n_vlib_mains - 1, 0); + } nat44_ei_add_del_addr_to_fib_foreach_out_if (addr, 1); @@ -2967,9 +3065,9 @@ nat44_ei_del_address (ip4_address_t addr, u8 delete_sm) pool_foreach (m, nm->static_mappings) { if (m->external_addr.as_u32 == addr.as_u32) - nat44_ei_del_static_mapping (m->local_addr, m->external_addr, - m->local_port, m->external_port, - m->proto, m->vrf_id, ~0, m->flags); + nat44_ei_del_static_mapping_internal ( + m->local_addr, m->external_addr, m->local_port, m->external_port, + m->proto, m->vrf_id, ~0, m->flags); } } else @@ -2982,13 +3080,9 @@ nat44_ei_del_address (ip4_address_t addr, u8 delete_sm) } } - if (a->fib_index != ~0) - { - fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low); - } - /* Delete sessions using address */ - if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports) + if (a->busy_ports[NAT_PROTOCOL_TCP] || a->busy_ports[NAT_PROTOCOL_UDP] || + a->busy_ports[NAT_PROTOCOL_ICMP]) { vec_foreach (tnm, nm->per_thread_data) { @@ -3010,14 +3104,20 @@ nat44_ei_del_address (ip4_address_t addr, u8 delete_sm) } } -#define _(N, i, n, s) vec_free (a->busy_##n##_ports_per_thread); - foreach_nat_protocol -#undef _ + nat44_ei_add_del_addr_to_fib_foreach_out_if (&addr, 0); - vec_del1 (nm->addresses, j); + if (a->fib_index != ~0) + { + fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low); + } - nat44_ei_add_del_addr_to_fib_foreach_out_if (&addr, 0); + nat_protocol_t proto; + for (proto = 0; proto < NAT_N_PROTOCOLS; ++proto) + { + vec_free (a->busy_ports_per_thread[proto]); + } + vec_del1 (nm->addresses, j); return 0; } @@ -3164,13 +3264,13 @@ nat44_ei_ip4_add_del_interface_address_cb (ip4_main_t *im, uword opaque, /* On this interface? */ if (rp->sw_if_index == sw_if_index) { - rv = nat44_ei_add_static_mapping ( + rv = nat44_ei_add_static_mapping_internal ( rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, rp->vrf_id, ~0, rp->flags, rp->pool_addr, rp->tag); if (rv) { - nat_elog_notice_X1 (nm, "add_static_mapping returned %d", - "i4", rv); + nat_elog_notice_X1 ( + nm, "add_static_mapping_internal returned %d", "i4", rv); } } } @@ -3236,9 +3336,9 @@ nat44_ei_ip4_add_del_addr_only_sm_cb (ip4_main_t *im, uword opaque, { if (!m) return; - rv = nat44_ei_del_static_mapping (rp->l_addr, address[0], rp->l_port, - rp->e_port, rp->proto, rp->vrf_id, ~0, - rp->flags); + rv = nat44_ei_del_static_mapping_internal ( + rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, rp->vrf_id, + ~0, rp->flags); if (rv) { nat_elog_notice_X1 (nm, "nat44_ei_del_static_mapping returned %d", @@ -3249,9 +3349,10 @@ nat44_ei_ip4_add_del_addr_only_sm_cb (ip4_main_t *im, uword opaque, { if (m) return; - rv = nat44_ei_add_static_mapping (rp->l_addr, address[0], rp->l_port, - rp->e_port, rp->proto, rp->vrf_id, ~0, - rp->flags, rp->pool_addr, rp->tag); + rv = nat44_ei_add_static_mapping_internal ( + rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, rp->vrf_id, + ~0, rp->flags, rp->pool_addr, rp->tag); + if (rv) { nat_elog_notice_X1 (nm, "nat44_ei_add_static_mapping returned %d", diff --git a/src/plugins/nat/nat44-ei/nat44_ei.h b/src/plugins/nat/nat44-ei/nat44_ei.h index 0134c7882dd..b4aa0f26c0b 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei.h +++ b/src/plugins/nat/nat44-ei/nat44_ei.h @@ -63,19 +63,17 @@ typedef enum #define NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO (1 << 1) /* Static mapping flags */ -#define NAT44_EI_SM_FLAG_ADDR_ONLY (1 << 0) -#define NAT44_EI_SM_FLAG_IDENTITY_NAT (1 << 1) +#define NAT44_EI_SM_FLAG_ADDR_ONLY (1 << 0) +#define NAT44_EI_SM_FLAG_IDENTITY_NAT (1 << 1) +#define NAT44_EI_SM_FLAG_SWITCH_ADDRESS (1 << 2) typedef struct { ip4_address_t addr; u32 fib_index; -#define _(N, i, n, s) \ - u32 busy_##n##_ports; \ - u32 *busy_##n##_ports_per_thread; \ - u32 busy_##n##_port_refcounts[0xffff + 1]; - foreach_nat_protocol -#undef _ + u32 busy_ports[NAT_N_PROTOCOLS]; + u32 *busy_ports_per_thread[NAT_N_PROTOCOLS]; + uword *busy_port_bitmap[NAT_N_PROTOCOLS]; } nat44_ei_address_t; clib_error_t *nat44_ei_api_hookup (vlib_main_t *vm); @@ -469,12 +467,14 @@ typedef struct nat44_ei_main_s /* nat44 plugin enabled */ u8 enabled; + /* hairpinning registration counter */ + u32 hairpin_reg; + nat44_ei_config_t rconfig; u32 in2out_hairpinning_finish_ip4_lookup_node_fq_index; u32 in2out_hairpinning_finish_interface_output_node_fq_index; u32 hairpinning_fq_index; - u32 hairpin_dst_fq_index; vnet_main_t *vnet_main; } nat44_ei_main_t; @@ -484,9 +484,10 @@ extern nat44_ei_main_t nat44_ei_main; int nat44_ei_plugin_enable (nat44_ei_config_t c); int nat44_ei_plugin_disable (); -int nat44_ei_add_del_interface (u32 sw_if_index, u8 is_inside, int is_del); -int nat44_ei_add_del_output_interface (u32 sw_if_index, int is_del); - +int nat44_ei_add_interface (u32 sw_if_index, u8 is_inside); +int nat44_ei_del_interface (u32 sw_if_index, u8 is_inside); +int nat44_ei_add_output_interface (u32 sw_if_index); +int nat44_ei_del_output_interface (u32 sw_if_index); int nat44_ei_add_address (ip4_address_t *addr, u32 vrf_id); int nat44_ei_del_address (ip4_address_t addr, u8 delete_sm); int nat44_ei_add_interface_address (u32 sw_if_index); @@ -624,21 +625,6 @@ void nat44_ei_delete_session (nat44_ei_main_t *nm, nat44_ei_session_t *ses, int nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t *kv, void *arg); int nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t *kv, void *arg); -int nat44_ei_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, - nat44_ei_main_t *nm, u32 thread_index, - vlib_buffer_t *b0, ip4_header_t *ip0, - udp_header_t *udp0, tcp_header_t *tcp0, u32 proto0, - int do_trace, u32 *required_thread_index); - -void nat44_ei_hairpinning_sm_unknown_proto (nat44_ei_main_t *nm, - vlib_buffer_t *b, - ip4_header_t *ip); - -u32 nat44_ei_icmp_hairpinning (nat44_ei_main_t *nm, vlib_buffer_t *b0, - u32 thread_index, ip4_header_t *ip0, - icmp46_header_t *icmp0, - u32 *required_thread_index); - int nat44_ei_set_frame_queue_nelts (u32 frame_queue_nelts); always_inline bool @@ -677,6 +663,12 @@ is_sm_identity_nat (u32 f) return (f & NAT44_EI_SM_FLAG_IDENTITY_NAT); } +always_inline bool +is_sm_switch_address (u32 f) +{ + return (f & NAT44_EI_SM_FLAG_SWITCH_ADDRESS); +} + /* logging */ #define nat44_ei_log_err(...) \ vlib_log (VLIB_LOG_LEVEL_ERR, nat44_ei_main.log_class, __VA_ARGS__) diff --git a/src/plugins/nat/nat44-ei/nat44_ei_api.c b/src/plugins/nat/nat44-ei/nat44_ei_api.c index c6d17c94205..454a5032c6a 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_api.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_api.c @@ -173,7 +173,9 @@ vl_api_nat44_ei_plugin_enable_disable_t_handler ( rv = nat44_ei_plugin_enable (c); } else - rv = nat44_ei_plugin_disable (); + { + rv = nat44_ei_plugin_disable (); + } REPLY_MACRO (VL_API_NAT44_EI_PLUGIN_ENABLE_DISABLE_REPLY); } @@ -533,18 +535,22 @@ vl_api_nat44_ei_interface_add_del_feature_t_handler ( nat44_ei_main_t *nm = &nat44_ei_main; vl_api_nat44_ei_interface_add_del_feature_reply_t *rmp; u32 sw_if_index = ntohl (mp->sw_if_index); - u8 is_del; int rv = 0; - is_del = !mp->is_add; - VALIDATE_SW_IF_INDEX (mp); - rv = nat44_ei_add_del_interface (sw_if_index, mp->flags & NAT44_EI_IF_INSIDE, - is_del); + if (mp->is_add) + { + rv = + nat44_ei_add_interface (sw_if_index, mp->flags & NAT44_EI_IF_INSIDE); + } + else + { + rv = + nat44_ei_del_interface (sw_if_index, mp->flags & NAT44_EI_IF_INSIDE); + } BAD_SW_IF_INDEX_LABEL; - REPLY_MACRO (VL_API_NAT44_EI_INTERFACE_ADD_DEL_FEATURE_REPLY); } @@ -648,7 +654,14 @@ vl_api_nat44_ei_interface_add_del_output_feature_t_handler ( if (!(mp->flags & NAT44_EI_IF_INSIDE)) { - rv = nat44_ei_add_del_output_interface (sw_if_index, !mp->is_add); + if (mp->is_add) + { + rv = nat44_ei_add_output_interface (sw_if_index); + } + else + { + rv = nat44_ei_del_output_interface (sw_if_index); + } } BAD_SW_IF_INDEX_LABEL; @@ -702,17 +715,21 @@ vl_api_nat44_ei_add_del_output_interface_t_handler ( { vl_api_nat44_ei_add_del_output_interface_reply_t *rmp; nat44_ei_main_t *nm = &nat44_ei_main; - u32 sw_if_index; int rv = 0; - VALIDATE_SW_IF_INDEX (mp); + VALIDATE_SW_IF_INDEX_END (mp); - sw_if_index = ntohl (mp->sw_if_index); - - rv = nat44_ei_add_del_output_interface (sw_if_index, !mp->is_add); + if (mp->is_add) + { + rv = nat44_ei_add_output_interface (mp->sw_if_index); + } + else + { + rv = nat44_ei_del_output_interface (mp->sw_if_index); + } - BAD_SW_IF_INDEX_LABEL; - REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_OUTPUT_INTERFACE_REPLY); +bad_sw_if_index: + REPLY_MACRO_END (VL_API_NAT44_EI_ADD_DEL_OUTPUT_INTERFACE_REPLY); } #define vl_endianfun @@ -734,7 +751,8 @@ send_nat44_ei_output_interface_details (u32 index, vl_api_registration_t *rp, /* Endian hack until apigen registers _details * endian functions */ - vl_api_nat44_ei_output_interface_details_t_endian (rmp); + vl_api_nat44_ei_output_interface_details_t_endian (rmp, + 1 /* to network */); rmp->_vl_msg_id = htons (rmp->_vl_msg_id); rmp->context = htonl (rmp->context); })); @@ -790,7 +808,7 @@ vl_api_nat44_ei_add_del_static_mapping_t_handler ( sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index); if (sw_if_index != ~0) { - e_addr.as_u32 = 0; + flags |= NAT44_EI_SM_FLAG_SWITCH_ADDRESS; } else { @@ -945,7 +963,7 @@ vl_api_nat44_ei_add_del_identity_mapping_t_handler ( sw_if_index = clib_net_to_host_u32 (mp->sw_if_index); if (sw_if_index != ~0) { - addr.as_u32 = 0; + flags |= NAT44_EI_SM_FLAG_SWITCH_ADDRESS; } else { @@ -1202,6 +1220,44 @@ send_nat44_ei_user_session_details (nat44_ei_session_t *s, } static void +send_nat44_ei_user_session_v2_details (nat44_ei_session_t *s, + vl_api_registration_t *reg, u32 context) +{ + vl_api_nat44_ei_user_session_v2_details_t *rmp; + nat44_ei_main_t *nm = &nat44_ei_main; + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + clib_memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = + ntohs (VL_API_NAT44_EI_USER_SESSION_V2_DETAILS + nm->msg_id_base); + clib_memcpy (rmp->outside_ip_address, (&s->out2in.addr), 4); + clib_memcpy (rmp->inside_ip_address, (&s->in2out.addr), 4); + + if (nat44_ei_is_session_static (s)) + rmp->flags |= NAT44_EI_STATIC_MAPPING; + + rmp->last_heard = clib_host_to_net_u64 ((u64) s->last_heard); + rmp->time_since_last_heard = clib_host_to_net_u64 ( + (u64) (vlib_time_now (vlib_get_main ()) - s->last_heard)); + rmp->total_bytes = clib_host_to_net_u64 (s->total_bytes); + rmp->total_pkts = ntohl (s->total_pkts); + rmp->context = context; + if (nat44_ei_is_unk_proto_session (s)) + { + rmp->outside_port = 0; + rmp->inside_port = 0; + rmp->protocol = ntohs (s->in2out.port); + } + else + { + rmp->outside_port = s->out2in.port; + rmp->inside_port = s->in2out.port; + rmp->protocol = ntohs (nat_proto_to_ip_proto (s->nat_proto)); + } + vl_api_send_msg (reg, (u8 *) rmp); +} + +static void vl_api_nat44_ei_user_session_dump_t_handler ( vl_api_nat44_ei_user_session_dump_t *mp) { @@ -1255,6 +1311,59 @@ vl_api_nat44_ei_user_session_dump_t_handler ( } static void +vl_api_nat44_ei_user_session_v2_dump_t_handler ( + vl_api_nat44_ei_user_session_dump_t *mp) +{ + vl_api_registration_t *reg; + nat44_ei_main_t *nm = &nat44_ei_main; + nat44_ei_main_per_thread_data_t *tnm; + nat44_ei_session_t *s; + clib_bihash_kv_8_8_t key, value; + nat44_ei_user_key_t ukey; + nat44_ei_user_t *u; + u32 session_index, head_index, elt_index; + dlist_elt_t *head, *elt; + ip4_header_t ip; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + clib_memcpy (&ukey.addr, mp->ip_address, 4); + ip.src_address.as_u32 = ukey.addr.as_u32; + ukey.fib_index = fib_table_find (FIB_PROTOCOL_IP4, ntohl (mp->vrf_id)); + key.key = ukey.as_u64; + if (nm->num_workers > 1) + tnm = vec_elt_at_index ( + nm->per_thread_data, + nat44_ei_get_in2out_worker_index (&ip, ukey.fib_index, 0)); + else + tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers); + + if (clib_bihash_search_8_8 (&tnm->user_hash, &key, &value)) + return; + u = pool_elt_at_index (tnm->users, value.value); + if (!u->nsessions && !u->nstaticsessions) + return; + + head_index = u->sessions_per_user_list_head_index; + head = pool_elt_at_index (tnm->list_pool, head_index); + elt_index = head->next; + elt = pool_elt_at_index (tnm->list_pool, elt_index); + session_index = elt->value; + while (session_index != ~0) + { + s = pool_elt_at_index (tnm->sessions, session_index); + + send_nat44_ei_user_session_v2_details (s, reg, mp->context); + + elt_index = elt->next; + elt = pool_elt_at_index (tnm->list_pool, elt_index); + session_index = elt->value; + } +} + +static void vl_api_nat44_ei_del_session_t_handler (vl_api_nat44_ei_del_session_t *mp) { nat44_ei_main_t *nm = &nat44_ei_main; diff --git a/src/plugins/nat/nat44-ei/nat44_ei_cli.c b/src/plugins/nat/nat44-ei/nat44_ei_cli.c index f3e71982e5c..eab50a4bc6c 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_cli.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_cli.c @@ -338,7 +338,7 @@ nat44_ei_set_log_level_command_fn (vlib_main_t *vm, unformat_input_t *input, { unformat_input_t _line_input, *line_input = &_line_input; nat44_ei_main_t *nm = &nat44_ei_main; - u8 log_level = NAT_LOG_NONE; + u32 log_level = NAT_LOG_NONE; clib_error_t *error = 0; if (!unformat_user (input, unformat_line_input, line_input)) @@ -841,7 +841,7 @@ nat44_ei_show_addresses_command_fn (vlib_main_t *vm, unformat_input_t *input, else vlib_cli_output (vm, " tenant VRF independent"); #define _(N, i, n, s) \ - vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s); + vlib_cli_output (vm, " %d busy %s ports", ap->busy_ports[i], s); foreach_nat_protocol #undef _ } @@ -859,8 +859,7 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input, u32 *inside_sw_if_indices = 0; u32 *outside_sw_if_indices = 0; u8 is_output_feature = 0; - int is_del = 0; - int i; + int i, rv, is_del = 0; sw_if_index = ~0; @@ -894,7 +893,15 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input, sw_if_index = inside_sw_if_indices[i]; if (is_output_feature) { - if (nat44_ei_add_del_output_interface (sw_if_index, is_del)) + if (is_del) + { + rv = nat44_ei_del_output_interface (sw_if_index); + } + else + { + rv = nat44_ei_add_output_interface (sw_if_index); + } + if (rv) { error = clib_error_return ( 0, "%s %U failed", is_del ? "del" : "add", @@ -904,7 +911,15 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input, } else { - if (nat44_ei_add_del_interface (sw_if_index, 1, is_del)) + if (is_del) + { + rv = nat44_ei_del_interface (sw_if_index, 1); + } + else + { + rv = nat44_ei_add_interface (sw_if_index, 1); + } + if (rv) { error = clib_error_return ( 0, "%s %U failed", is_del ? "del" : "add", @@ -922,7 +937,15 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input, sw_if_index = outside_sw_if_indices[i]; if (is_output_feature) { - if (nat44_ei_add_del_output_interface (sw_if_index, is_del)) + if (is_del) + { + rv = nat44_ei_del_output_interface (sw_if_index); + } + else + { + rv = nat44_ei_add_output_interface (sw_if_index); + } + if (rv) { error = clib_error_return ( 0, "%s %U failed", is_del ? "del" : "add", @@ -932,7 +955,15 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input, } else { - if (nat44_ei_add_del_interface (sw_if_index, 0, is_del)) + if (is_del) + { + rv = nat44_ei_del_interface (sw_if_index, 0); + } + else + { + rv = nat44_ei_add_interface (sw_if_index, 0); + } + if (rv) { error = clib_error_return ( 0, "%s %U failed", is_del ? "del" : "add", @@ -1061,6 +1092,11 @@ add_static_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input, e_port = clib_host_to_net_u16 (e_port); } + if (sw_if_index != ~0) + { + flags |= NAT44_EI_SM_FLAG_SWITCH_ADDRESS; + } + if (is_add) { rv = @@ -1112,7 +1148,7 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input, int rv, is_add = 1, port_set = 0; u32 sw_if_index = ~0, port, flags, vrf_id = ~0; - nat_protocol_t proto; + nat_protocol_t proto = NAT_PROTOCOL_OTHER; ip4_address_t addr; flags = NAT44_EI_SM_FLAG_IDENTITY_NAT; @@ -1155,6 +1191,11 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input, port = clib_host_to_net_u16 (port); } + if (sw_if_index != ~0) + { + flags |= NAT44_EI_SM_FLAG_SWITCH_ADDRESS; + } + if (is_add) { @@ -1548,23 +1589,23 @@ nat_show_timeouts_command_fn (vlib_main_t *vm, unformat_input_t *input, * @cliexstart{nat44 ei} * Enable nat44 ei plugin * To enable nat44-ei, use: - * vpp# nat44 ei enable + * vpp# nat44 ei plugin enable * To disable nat44-ei, use: - * vpp# nat44 ei disable + * vpp# nat44 ei plugin disable * To enable nat44 ei static mapping only, use: - * vpp# nat44 ei enable static-mapping + * vpp# nat44 ei plugin enable static-mapping * To enable nat44 ei static mapping with connection tracking, use: - * vpp# nat44 ei enable static-mapping connection-tracking + * vpp# nat44 ei plugin enable static-mapping connection-tracking * To enable nat44 ei out2in dpo, use: - * vpp# nat44 ei enable out2in-dpo + * vpp# nat44 ei plugin enable out2in-dpo * To set inside-vrf outside-vrf, use: - * vpp# nat44 ei enable inside-vrf <id> outside-vrf <id> + * vpp# nat44 ei plugin enable inside-vrf <id> outside-vrf <id> * @cliexend ?*/ VLIB_CLI_COMMAND (nat44_ei_enable_disable_command, static) = { - .path = "nat44 ei", + .path = "nat44 ei plugin", .short_help = - "nat44 ei <enable [sessions <max-number>] [users <max-number>] " + "nat44 ei plugin <enable [sessions <max-number>] [users <max-number>] " "[static-mappig-only [connection-tracking]|out2in-dpo] [inside-vrf " "<vrf-id>] [outside-vrf <vrf-id>] [user-sessions <max-number>]>|disable", .function = nat44_ei_enable_disable_command_fn, diff --git a/src/plugins/nat/nat44-ei/nat44_ei_ha.c b/src/plugins/nat/nat44-ei/nat44_ei_ha.c index 39bce255bd6..9546a595cc2 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_ha.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_ha.c @@ -926,14 +926,12 @@ nat_ha_worker_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, return 0; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat_ha_worker_node) = { .function = nat_ha_worker_fn, .type = VLIB_NODE_TYPE_INPUT, .state = VLIB_NODE_STATE_INTERRUPT, .name = "nat44-ei-ha-worker", }; -/* *INDENT-ON* */ /* periodically send interrupt to each thread */ static uword @@ -969,13 +967,11 @@ nat_ha_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) return 0; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat_ha_process_node) = { .function = nat_ha_process, .type = VLIB_NODE_TYPE_PROCESS, .name = "nat44-ei-ha-process", }; -/* *INDENT-ON* */ void nat_ha_get_resync_status (u8 * in_resync, u32 * resync_ack_missed) @@ -1166,7 +1162,6 @@ nat_ha_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat_ha_node) = { .function = nat_ha_node_fn, .name = "nat44-ei-ha", @@ -1181,7 +1176,6 @@ VLIB_REGISTER_NODE (nat_ha_node) = { [NAT_HA_NEXT_DROP] = "error-drop", }, }; -/* *INDENT-ON* */ typedef struct { @@ -1286,7 +1280,6 @@ nat_ha_resync (u32 client_index, u32 pid, return 0; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat_ha_handoff_node) = { .function = nat_ha_handoff_node_fn, .name = "nat44-ei-ha-handoff", @@ -1300,7 +1293,6 @@ VLIB_REGISTER_NODE (nat_ha_handoff_node) = { [0] = "error-drop", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/nat44-ei/nat44_ei_hairpinning.c b/src/plugins/nat/nat44-ei/nat44_ei_hairpinning.c deleted file mode 100644 index c3d3cfba386..00000000000 --- a/src/plugins/nat/nat44-ei/nat44_ei_hairpinning.c +++ /dev/null @@ -1,759 +0,0 @@ -/* - * nat44_ei.c - nat44 endpoint dependent plugin - * * Copyright (c) 2020 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. - */ - -#include <vlib/vlib.h> -#include <vnet/vnet.h> -#include <vnet/fib/ip4_fib.h> - -#include <nat/nat44-ei/nat44_ei.h> -#include <nat/nat44-ei/nat44_ei_inlines.h> -#include <nat/nat44-ei/nat44_ei_hairpinning.h> - -/* NAT buffer flags */ -#define NAT44_EI_FLAG_HAIRPINNING (1 << 0) - -typedef enum -{ - NAT44_EI_HAIRPIN_SRC_NEXT_DROP, - NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT, - NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH, - NAT44_EI_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT, - NAT44_EI_HAIRPIN_SRC_N_NEXT, -} nat44_ei_hairpin_src_next_t; - -typedef enum -{ - NAT44_EI_HAIRPIN_NEXT_LOOKUP, - NAT44_EI_HAIRPIN_NEXT_DROP, - NAT44_EI_HAIRPIN_NEXT_HANDOFF, - NAT44_EI_HAIRPIN_N_NEXT, -} nat44_ei_hairpin_next_t; - -typedef struct -{ - ip4_address_t addr; - u16 port; - u32 fib_index; - u32 session_index; -} nat44_ei_hairpin_trace_t; - -static u8 * -format_nat44_ei_hairpin_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_ei_hairpin_trace_t *t = va_arg (*args, nat44_ei_hairpin_trace_t *); - - s = format (s, "new dst addr %U port %u fib-index %u", format_ip4_address, - &t->addr, clib_net_to_host_u16 (t->port), t->fib_index); - if (~0 == t->session_index) - { - s = format (s, " is-static-mapping"); - } - else - { - s = format (s, " session-index %u", t->session_index); - } - - return s; -} - -extern vnet_feature_arc_registration_t vnet_feat_arc_ip4_local; - -static_always_inline int -nat44_ei_is_hairpinning (nat44_ei_main_t *nm, ip4_address_t *dst_addr) -{ - nat44_ei_address_t *ap; - clib_bihash_kv_8_8_t kv, value; - - vec_foreach (ap, nm->addresses) - { - if (ap->addr.as_u32 == dst_addr->as_u32) - return 1; - } - - init_nat_k (&kv, *dst_addr, 0, 0, 0); - if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value)) - return 1; - - return 0; -} - -#ifndef CLIB_MARCH_VARIANT -void -nat44_ei_hairpinning_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b, - ip4_header_t *ip) -{ - clib_bihash_kv_8_8_t kv, value; - nat44_ei_static_mapping_t *m; - u32 old_addr, new_addr; - ip_csum_t sum; - - init_nat_k (&kv, ip->dst_address, 0, 0, 0); - if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value)) - return; - - m = pool_elt_at_index (nm->static_mappings, value.value); - - old_addr = ip->dst_address.as_u32; - new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32; - sum = ip->checksum; - sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address); - ip->checksum = ip_csum_fold (sum); - - if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0) - vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index; -} -#endif - -#ifndef CLIB_MARCH_VARIANT -int -nat44_ei_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, - nat44_ei_main_t *nm, u32 thread_index, vlib_buffer_t *b0, - ip4_header_t *ip0, udp_header_t *udp0, - tcp_header_t *tcp0, u32 proto0, int do_trace, - u32 *required_thread_index) -{ - nat44_ei_session_t *s0 = NULL; - clib_bihash_kv_8_8_t kv0, value0; - ip_csum_t sum0; - u32 new_dst_addr0 = 0, old_dst_addr0, si = ~0; - u16 new_dst_port0 = ~0, old_dst_port0; - int rv; - ip4_address_t sm0_addr; - u16 sm0_port; - u32 sm0_fib_index; - u32 old_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - - /* Check if destination is static mappings */ - if (!nat44_ei_static_mapping_match ( - ip0->dst_address, udp0->dst_port, nm->outside_fib_index, proto0, - &sm0_addr, &sm0_port, &sm0_fib_index, 1 /* by external */, 0, 0)) - { - new_dst_addr0 = sm0_addr.as_u32; - new_dst_port0 = sm0_port; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0_fib_index; - } - /* or active session */ - else - { - init_nat_k (&kv0, ip0->dst_address, udp0->dst_port, - nm->outside_fib_index, proto0); - rv = clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0); - if (rv) - { - rv = 0; - goto trace; - } - - if (thread_index != nat_value_get_thread_index (&value0)) - { - *required_thread_index = nat_value_get_thread_index (&value0); - return 0; - } - - si = nat_value_get_session_index (&value0); - s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions, si); - new_dst_addr0 = s0->in2out.addr.as_u32; - new_dst_port0 = s0->in2out.port; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - } - - /* Check if anything has changed and if not, then return 0. This - helps avoid infinite loop, repeating the three nodes - nat44-hairpinning-->ip4-lookup-->ip4-local, in case nothing has - changed. */ - old_dst_addr0 = ip0->dst_address.as_u32; - old_dst_port0 = tcp0->dst; - if (new_dst_addr0 == old_dst_addr0 && new_dst_port0 == old_dst_port0 && - vnet_buffer (b0)->sw_if_index[VLIB_TX] == old_sw_if_index) - return 0; - - /* Destination is behind the same NAT, use internal address and port */ - if (new_dst_addr0) - { - old_dst_addr0 = ip0->dst_address.as_u32; - ip0->dst_address.as_u32 = new_dst_addr0; - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, ip4_header_t, - dst_address); - ip0->checksum = ip_csum_fold (sum0); - - old_dst_port0 = tcp0->dst; - if (PREDICT_TRUE (new_dst_port0 != old_dst_port0)) - { - if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP)) - { - tcp0->dst = new_dst_port0; - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, - ip4_header_t, dst_address); - sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0, - ip4_header_t /* cheat */, length); - tcp0->checksum = ip_csum_fold (sum0); - } - else - { - udp0->dst_port = new_dst_port0; - udp0->checksum = 0; - } - } - else - { - if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP)) - { - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, - ip4_header_t, dst_address); - tcp0->checksum = ip_csum_fold (sum0); - } - } - rv = 1; - goto trace; - } - rv = 0; -trace: - if (do_trace && PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && - (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - nat44_ei_hairpin_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->addr.as_u32 = new_dst_addr0; - t->port = new_dst_port0; - t->fib_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - if (s0) - { - t->session_index = si; - } - else - { - t->session_index = ~0; - } - } - return rv; -} -#endif - -#ifndef CLIB_MARCH_VARIANT -u32 -nat44_ei_icmp_hairpinning (nat44_ei_main_t *nm, vlib_buffer_t *b0, - u32 thread_index, ip4_header_t *ip0, - icmp46_header_t *icmp0, u32 *required_thread_index) -{ - clib_bihash_kv_8_8_t kv0, value0; - u32 old_dst_addr0, new_dst_addr0; - u32 old_addr0, new_addr0; - u16 old_port0, new_port0; - u16 old_checksum0, new_checksum0; - u32 si, ti = 0; - ip_csum_t sum0; - nat44_ei_session_t *s0; - nat44_ei_static_mapping_t *m0; - - if (icmp_type_is_error_message ( - vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags)) - { - ip4_header_t *inner_ip0 = 0; - tcp_udp_header_t *l4_header = 0; - - inner_ip0 = (ip4_header_t *) ((icmp_echo_header_t *) (icmp0 + 1) + 1); - l4_header = ip4_next_header (inner_ip0); - u32 protocol = ip_proto_to_nat_proto (inner_ip0->protocol); - - if (protocol != NAT_PROTOCOL_TCP && protocol != NAT_PROTOCOL_UDP) - return 1; - - init_nat_k (&kv0, ip0->dst_address, l4_header->src_port, - nm->outside_fib_index, protocol); - if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0)) - return 1; - ti = nat_value_get_thread_index (&value0); - if (ti != thread_index) - { - *required_thread_index = ti; - return 1; - } - si = nat_value_get_session_index (&value0); - s0 = pool_elt_at_index (nm->per_thread_data[ti].sessions, si); - new_dst_addr0 = s0->in2out.addr.as_u32; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - - /* update inner source IP address */ - old_addr0 = inner_ip0->src_address.as_u32; - inner_ip0->src_address.as_u32 = new_dst_addr0; - new_addr0 = inner_ip0->src_address.as_u32; - sum0 = icmp0->checksum; - sum0 = - ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, src_address); - icmp0->checksum = ip_csum_fold (sum0); - - /* update inner IP header checksum */ - old_checksum0 = inner_ip0->checksum; - sum0 = inner_ip0->checksum; - sum0 = - ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, src_address); - inner_ip0->checksum = ip_csum_fold (sum0); - new_checksum0 = inner_ip0->checksum; - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_checksum0, new_checksum0, ip4_header_t, - checksum); - icmp0->checksum = ip_csum_fold (sum0); - - /* update inner source port */ - old_port0 = l4_header->src_port; - l4_header->src_port = s0->in2out.port; - new_port0 = l4_header->src_port; - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, old_port0, new_port0, tcp_udp_header_t, - src_port); - icmp0->checksum = ip_csum_fold (sum0); - } - else - { - init_nat_k (&kv0, ip0->dst_address, 0, nm->outside_fib_index, 0); - if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv0, - &value0)) - { - icmp_echo_header_t *echo0 = (icmp_echo_header_t *) (icmp0 + 1); - u16 icmp_id0 = echo0->identifier; - init_nat_k (&kv0, ip0->dst_address, icmp_id0, nm->outside_fib_index, - NAT_PROTOCOL_ICMP); - int rv = clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0); - if (!rv) - { - ti = nat_value_get_thread_index (&value0); - if (ti != thread_index) - { - *required_thread_index = ti; - return 1; - } - si = nat_value_get_session_index (&value0); - s0 = pool_elt_at_index (nm->per_thread_data[ti].sessions, si); - new_dst_addr0 = s0->in2out.addr.as_u32; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; - echo0->identifier = s0->in2out.port; - sum0 = icmp0->checksum; - sum0 = ip_csum_update (sum0, icmp_id0, s0->in2out.port, - icmp_echo_header_t, identifier); - icmp0->checksum = ip_csum_fold (sum0); - goto change_addr; - } - - return 1; - } - - m0 = pool_elt_at_index (nm->static_mappings, value0.value); - - new_dst_addr0 = m0->local_addr.as_u32; - if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0) - vnet_buffer (b0)->sw_if_index[VLIB_TX] = m0->fib_index; - } -change_addr: - /* Destination is behind the same NAT, use internal address and port */ - if (new_dst_addr0) - { - old_dst_addr0 = ip0->dst_address.as_u32; - ip0->dst_address.as_u32 = new_dst_addr0; - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, ip4_header_t, - dst_address); - ip0->checksum = ip_csum_fold (sum0); - } - return 0; -} -#endif - -void nat44_ei_hairpinning_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b, - ip4_header_t *ip); - -#ifndef CLIB_MARCH_VARIANT -void -nat44_ei_hairpinning_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b, - ip4_header_t *ip) -{ - clib_bihash_kv_8_8_t kv, value; - nat44_ei_static_mapping_t *m; - u32 old_addr, new_addr; - ip_csum_t sum; - - init_nat_k (&kv, ip->dst_address, 0, 0, 0); - if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value)) - return; - - m = pool_elt_at_index (nm->static_mappings, value.value); - - old_addr = ip->dst_address.as_u32; - new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32; - sum = ip->checksum; - sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address); - ip->checksum = ip_csum_fold (sum); - - if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0) - vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index; -} -#endif - -VLIB_NODE_FN (nat44_ei_hairpin_src_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - u32 n_left_from, *from, *to_next; - nat44_ei_hairpin_src_next_t next_index; - nat44_ei_main_t *nm = &nat44_ei_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - 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; - vlib_buffer_t *b0; - u32 next0; - nat44_ei_interface_t *i; - u32 rx_sw_if_index0; - u32 tx_sw_if_index0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - tx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - - pool_foreach (i, nm->output_feature_interfaces) - { - /* Only packets from NAT inside interface */ - if ((nat44_ei_interface_is_inside (i)) && - (rx_sw_if_index0 == i->sw_if_index)) - { - if (PREDICT_FALSE ((vnet_buffer (b0)->snat.flags) & - NAT44_EI_FLAG_HAIRPINNING)) - { - if (PREDICT_TRUE (nm->num_workers > 1)) - { - next0 = NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH; - goto skip_feature_next; - } - else - { - next0 = NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT; - goto skip_feature_next; - } - } - break; - } - } - - vnet_feature_next (&next0, b0); - skip_feature_next: - - if (next0 != NAT44_EI_HAIRPIN_SRC_NEXT_DROP) - { - vlib_increment_simple_counter (&nm->counters.hairpinning, - vm->thread_index, tx_sw_if_index0, - 1); - } - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -VLIB_NODE_FN (nat44_ei_hairpin_dst_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - u32 n_left_from, *from, *to_next; - u32 thread_index = vm->thread_index; - nat44_ei_hairpin_next_t next_index; - nat44_ei_main_t *nm = &nat44_ei_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - 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; - vlib_buffer_t *b0; - u32 next0; - ip4_header_t *ip0; - u32 proto0; - u32 sw_if_index0; - u32 required_thread_index = thread_index; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - next0 = NAT44_EI_HAIRPIN_NEXT_LOOKUP; - ip0 = vlib_buffer_get_current (b0); - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - - proto0 = ip_proto_to_nat_proto (ip0->protocol); - - vnet_buffer (b0)->snat.flags = 0; - if (PREDICT_FALSE (nat44_ei_is_hairpinning (nm, &ip0->dst_address))) - { - if (proto0 == NAT_PROTOCOL_TCP || proto0 == NAT_PROTOCOL_UDP) - { - udp_header_t *udp0 = ip4_next_header (ip0); - tcp_header_t *tcp0 = (tcp_header_t *) udp0; - - nat44_ei_hairpinning (vm, node, nm, thread_index, b0, ip0, - udp0, tcp0, proto0, 1 /* do_trace */, - &required_thread_index); - } - else if (proto0 == NAT_PROTOCOL_ICMP) - { - icmp46_header_t *icmp0 = ip4_next_header (ip0); - - nat44_ei_icmp_hairpinning (nm, b0, thread_index, ip0, icmp0, - &required_thread_index); - } - else - { - nat44_ei_hairpinning_unknown_proto (nm, b0, ip0); - } - - vnet_buffer (b0)->snat.flags = NAT44_EI_FLAG_HAIRPINNING; - } - - if (thread_index != required_thread_index) - { - vnet_buffer (b0)->snat.required_thread_index = - required_thread_index; - next0 = NAT44_EI_HAIRPIN_NEXT_HANDOFF; - } - - if (next0 != NAT44_EI_HAIRPIN_NEXT_DROP) - { - vlib_increment_simple_counter ( - &nm->counters.hairpinning, vm->thread_index, sw_if_index0, 1); - } - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -VLIB_NODE_FN (nat44_ei_hairpinning_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - u32 n_left_from, *from, *to_next; - u32 thread_index = vm->thread_index; - nat44_ei_hairpin_next_t next_index; - nat44_ei_main_t *nm = &nat44_ei_main; - vnet_feature_main_t *fm = &feature_main; - u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index; - vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index]; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - 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; - vlib_buffer_t *b0; - u32 next0; - ip4_header_t *ip0; - u32 proto0; - udp_header_t *udp0; - tcp_header_t *tcp0; - u32 sw_if_index0; - u32 required_thread_index = thread_index; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - - proto0 = ip_proto_to_nat_proto (ip0->protocol); - int next0_resolved = 0; - - if (nat44_ei_hairpinning (vm, node, nm, thread_index, b0, ip0, udp0, - tcp0, proto0, 1 /* do_trace */, - &required_thread_index)) - { - next0 = NAT44_EI_HAIRPIN_NEXT_LOOKUP; - next0_resolved = 1; - } - - if (thread_index != required_thread_index) - { - vnet_buffer (b0)->snat.required_thread_index = - required_thread_index; - next0 = NAT44_EI_HAIRPIN_NEXT_HANDOFF; - next0_resolved = 1; - } - - if (!next0_resolved) - vnet_get_config_data (&cm->config_main, &b0->current_config_index, - &next0, 0); - - if (next0 != NAT44_EI_HAIRPIN_NEXT_DROP) - { - vlib_increment_simple_counter ( - &nm->counters.hairpinning, vm->thread_index, sw_if_index0, 1); - } - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -VLIB_NODE_FN (nat44_ei_hairpinning_dst_handoff_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - return nat44_ei_hairpinning_handoff_fn_inline ( - vm, node, frame, nat44_ei_main.hairpin_dst_fq_index); -} - -VLIB_NODE_FN (nat44_ei_hairpinning_handoff_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - return nat44_ei_hairpinning_handoff_fn_inline ( - vm, node, frame, nat44_ei_main.hairpinning_fq_index); -} - -VLIB_REGISTER_NODE (nat44_ei_hairpinning_dst_handoff_node) = { - .name = "nat44-ei-hairpin-dst-handoff", - .vector_size = sizeof (u32), - .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings), - .error_strings = nat44_ei_hairpinning_handoff_error_strings, - .format_trace = format_nat44_ei_hairpinning_handoff_trace, - - .n_next_nodes = 1, - - .next_nodes = { - [0] = "error-drop", - }, -}; - -VLIB_REGISTER_NODE (nat44_ei_hairpinning_handoff_node) = { - .name = "nat44-ei-hairpinning-handoff", - .vector_size = sizeof (u32), - .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings), - .error_strings = nat44_ei_hairpinning_handoff_error_strings, - .format_trace = format_nat44_ei_hairpinning_handoff_trace, - - .n_next_nodes = 1, - - .next_nodes = { - [0] = "error-drop", - }, -}; - -VLIB_REGISTER_NODE (nat44_ei_hairpin_src_node) = { - .name = "nat44-ei-hairpin-src", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - .n_next_nodes = NAT44_EI_HAIRPIN_SRC_N_NEXT, - .next_nodes = { - [NAT44_EI_HAIRPIN_SRC_NEXT_DROP] = "error-drop", - [NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT] = "nat44-ei-in2out-output", - [NAT44_EI_HAIRPIN_SRC_NEXT_INTERFACE_OUTPUT] = "interface-output", - [NAT44_EI_HAIRPIN_SRC_NEXT_SNAT_IN2OUT_WH] = "nat44-ei-in2out-output-worker-handoff", - }, -}; - -VLIB_REGISTER_NODE (nat44_ei_hairpin_dst_node) = { - .name = "nat44-ei-hairpin-dst", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - .format_trace = format_nat44_ei_hairpin_trace, - .n_next_nodes = NAT44_EI_HAIRPIN_N_NEXT, - .next_nodes = { - [NAT44_EI_HAIRPIN_NEXT_DROP] = "error-drop", - [NAT44_EI_HAIRPIN_NEXT_LOOKUP] = "ip4-lookup", - [NAT44_EI_HAIRPIN_NEXT_HANDOFF] = "nat44-ei-hairpin-dst-handoff", - }, -}; - -VLIB_REGISTER_NODE (nat44_ei_hairpinning_node) = { - .name = "nat44-ei-hairpinning", - .vector_size = sizeof (u32), - .type = VLIB_NODE_TYPE_INTERNAL, - .format_trace = format_nat44_ei_hairpin_trace, - .n_next_nodes = NAT44_EI_HAIRPIN_N_NEXT, - .next_nodes = { - [NAT44_EI_HAIRPIN_NEXT_DROP] = "error-drop", - [NAT44_EI_HAIRPIN_NEXT_LOOKUP] = "ip4-lookup", - [NAT44_EI_HAIRPIN_NEXT_HANDOFF] = "nat44-ei-hairpinning-handoff", - }, -}; - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/nat44-ei/nat44_ei_hairpinning.h b/src/plugins/nat/nat44-ei/nat44_ei_hairpinning.h deleted file mode 100644 index 908e6b2cfc9..00000000000 --- a/src/plugins/nat/nat44-ei/nat44_ei_hairpinning.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef __included_nat44_ei_hairpinning_h__ -#define __included_nat44_ei_hairpinning_h__ - -#include <nat/nat44-ei/nat44_ei.h> - -#define foreach_nat44_ei_hairpinning_handoff_error \ - _ (CONGESTION_DROP, "congestion drop") - -typedef enum -{ -#define _(sym, str) NAT44_EI_HAIRPINNING_HANDOFF_ERROR_##sym, - foreach_nat44_ei_hairpinning_handoff_error -#undef _ - NAT44_EI_HAIRPINNING_HANDOFF_N_ERROR, -} nat44_ei_hairpinning_handoff_error_t; - -static char *nat44_ei_hairpinning_handoff_error_strings[] = { -#define _(sym, string) string, - foreach_nat44_ei_hairpinning_handoff_error -#undef _ -}; - -typedef struct -{ - u32 next_worker_index; -} nat44_ei_hairpinning_handoff_trace_t; - -static u8 * -format_nat44_ei_hairpinning_handoff_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_ei_hairpinning_handoff_trace_t *t = - va_arg (*args, nat44_ei_hairpinning_handoff_trace_t *); - - s = format (s, "nat44-ei-hairpinning-handoff: next-worker %d", - t->next_worker_index); - - return s; -} - -always_inline uword -nat44_ei_hairpinning_handoff_fn_inline (vlib_main_t *vm, - vlib_node_runtime_t *node, - vlib_frame_t *frame, u32 fq_index) -{ - vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; - u32 n_enq, n_left_from, *from; - u16 thread_indices[VLIB_FRAME_SIZE], *ti; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - vlib_get_buffers (vm, from, bufs, n_left_from); - - b = bufs; - ti = thread_indices; - - while (n_left_from > 0) - { - ti[0] = vnet_buffer (b[0])->snat.required_thread_index; - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && - (b[0]->flags & VLIB_BUFFER_IS_TRACED))) - { - nat44_ei_hairpinning_handoff_trace_t *t = - vlib_add_trace (vm, node, b[0], sizeof (*t)); - t->next_worker_index = ti[0]; - } - - n_left_from -= 1; - ti += 1; - b += 1; - } - n_enq = vlib_buffer_enqueue_to_thread (vm, node, fq_index, from, - thread_indices, frame->n_vectors, 1); - - if (n_enq < frame->n_vectors) - vlib_node_increment_counter ( - vm, node->node_index, NAT44_EI_HAIRPINNING_HANDOFF_ERROR_CONGESTION_DROP, - frame->n_vectors - n_enq); - return frame->n_vectors; -} - -#endif // __included_nat44_ei_hairpinning_h__ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/nat/nat44-ei/nat44_ei_handoff.c b/src/plugins/nat/nat44-ei/nat44_ei_handoff.c index 5c16d871c4d..f1821d7721f 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_handoff.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_handoff.c @@ -15,7 +15,6 @@ #include <vlib/vlib.h> #include <vnet/vnet.h> -#include <vnet/handoff.h> #include <vnet/fib/ip4_fib.h> #include <vppinfra/error.h> diff --git a/src/plugins/nat/nat44-ei/nat44_ei_in2out.c b/src/plugins/nat/nat44-ei/nat44_ei_in2out.c index a2fc5910584..3b981d69986 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_in2out.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_in2out.c @@ -34,50 +34,8 @@ #include <nat/lib/nat_inlines.h> #include <nat/nat44-ei/nat44_ei_inlines.h> #include <nat/nat44-ei/nat44_ei.h> -#include <nat/nat44-ei/nat44_ei_hairpinning.h> -typedef struct -{ - u32 sw_if_index; - u32 next_index; - u32 session_index; - u32 is_slow_path; - u32 is_hairpinning; -} nat44_ei_in2out_trace_t; - -/* packet trace format function */ -static u8 * -format_nat44_ei_in2out_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_ei_in2out_trace_t *t = va_arg (*args, nat44_ei_in2out_trace_t *); - char *tag; - - tag = t->is_slow_path ? "NAT44_IN2OUT_SLOW_PATH" : "NAT44_IN2OUT_FAST_PATH"; - - s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag, - t->sw_if_index, t->next_index, t->session_index); - if (t->is_hairpinning) - { - s = format (s, ", with-hairpinning"); - } - - return s; -} - -static u8 * -format_nat44_ei_in2out_fast_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_ei_in2out_trace_t *t = va_arg (*args, nat44_ei_in2out_trace_t *); - - s = format (s, "NAT44_IN2OUT_FAST: sw_if_index %d, next index %d", - t->sw_if_index, t->next_index); - - return s; -} +extern vnet_feature_arc_registration_t vnet_feat_arc_ip4_local; #define foreach_nat44_ei_in2out_error \ _ (UNSUPPORTED_PROTOCOL, "unsupported protocol") \ @@ -88,6 +46,9 @@ format_nat44_ei_in2out_fast_trace (u8 *s, va_list *args) _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \ _ (CANNOT_CREATE_USER, "cannot create NAT user") +#define foreach_nat44_ei_hairpinning_handoff_error \ + _ (CONGESTION_DROP, "congestion drop") + typedef enum { #define _(sym, str) NAT44_EI_IN2OUT_ERROR_##sym, @@ -104,6 +65,20 @@ static char *nat44_ei_in2out_error_strings[] = { typedef enum { +#define _(sym, str) NAT44_EI_HAIRPINNING_HANDOFF_ERROR_##sym, + foreach_nat44_ei_hairpinning_handoff_error +#undef _ + NAT44_EI_HAIRPINNING_HANDOFF_N_ERROR, +} nat44_ei_hairpinning_handoff_error_t; + +static char *nat44_ei_hairpinning_handoff_error_strings[] = { +#define _(sym, string) string, + foreach_nat44_ei_hairpinning_handoff_error +#undef _ +}; + +typedef enum +{ NAT44_EI_IN2OUT_NEXT_LOOKUP, NAT44_EI_IN2OUT_NEXT_DROP, NAT44_EI_IN2OUT_NEXT_ICMP_ERROR, @@ -119,7 +94,98 @@ typedef enum NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT, } nat44_ei_in2out_hairpinnig_finish_next_t; -static inline int +typedef enum +{ + NAT44_EI_HAIRPIN_NEXT_LOOKUP, + NAT44_EI_HAIRPIN_NEXT_DROP, + NAT44_EI_HAIRPIN_NEXT_HANDOFF, + NAT44_EI_HAIRPIN_N_NEXT, +} nat44_ei_hairpin_next_t; + +typedef struct +{ + u32 sw_if_index; + u32 next_index; + u32 session_index; + u32 is_slow_path; + u32 is_hairpinning; +} nat44_ei_in2out_trace_t; + +typedef struct +{ + ip4_address_t addr; + u16 port; + u32 fib_index; + u32 session_index; +} nat44_ei_hairpin_trace_t; + +typedef struct +{ + u32 next_worker_index; +} nat44_ei_hairpinning_handoff_trace_t; + +static u8 * +format_nat44_ei_in2out_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_ei_in2out_trace_t *t = va_arg (*args, nat44_ei_in2out_trace_t *); + char *tag; + tag = t->is_slow_path ? "NAT44_IN2OUT_SLOW_PATH" : "NAT44_IN2OUT_FAST_PATH"; + s = format (s, "%s: sw_if_index %d, next index %d, session %d", tag, + t->sw_if_index, t->next_index, t->session_index); + if (t->is_hairpinning) + s = format (s, ", with-hairpinning"); + return s; +} + +static u8 * +format_nat44_ei_in2out_fast_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_ei_in2out_trace_t *t = va_arg (*args, nat44_ei_in2out_trace_t *); + s = format (s, "NAT44_IN2OUT_FAST: sw_if_index %d, next index %d", + t->sw_if_index, t->next_index); + return s; +} + +static u8 * +format_nat44_ei_hairpin_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_ei_hairpin_trace_t *t = va_arg (*args, nat44_ei_hairpin_trace_t *); + + s = format (s, "new dst addr %U port %u fib-index %u", format_ip4_address, + &t->addr, clib_net_to_host_u16 (t->port), t->fib_index); + if (~0 == t->session_index) + { + s = format (s, " is-static-mapping"); + } + else + { + s = format (s, " session-index %u", t->session_index); + } + + return s; +} + +static u8 * +format_nat44_ei_hairpinning_handoff_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_ei_hairpinning_handoff_trace_t *t = + va_arg (*args, nat44_ei_hairpinning_handoff_trace_t *); + + s = format (s, "nat44-ei-hairpinning-handoff: next-worker %d", + t->next_worker_index); + + return s; +} + +static_always_inline int nat44_ei_not_translate_fast (vlib_node_runtime_t *node, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0) { @@ -177,7 +243,7 @@ nat44_ei_not_translate_fast (vlib_node_runtime_t *node, u32 sw_if_index0, return 1; } -static inline int +static_always_inline int nat44_ei_not_translate (nat44_ei_main_t *nm, vlib_node_runtime_t *node, u32 sw_if_index0, ip4_header_t *ip0, u32 proto0, u32 rx_fib_index0, u32 thread_index) @@ -212,7 +278,7 @@ nat44_ei_not_translate (nat44_ei_main_t *nm, vlib_node_runtime_t *node, rx_fib_index0); } -static inline int +static_always_inline int nat44_ei_not_translate_output_feature (nat44_ei_main_t *nm, ip4_header_t *ip0, u32 proto0, u16 src_port, u16 dst_port, u32 thread_index, u32 sw_if_index) @@ -443,7 +509,6 @@ slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_header_t *ip0, return next0; } -#ifndef CLIB_MARCH_VARIANT static_always_inline nat44_ei_in2out_error_t icmp_get_key (vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr, u16 *port, nat_protocol_t *nat_proto) @@ -488,22 +553,7 @@ icmp_get_key (vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr, return -1; /* success */ } -/** - * Get address and port values to be used for ICMP packet translation - * and create session if needed - * - * @param[in,out] nm NAT main - * @param[in,out] node NAT node runtime - * @param[in] thread_index thread index - * @param[in,out] b0 buffer containing packet to be translated - * @param[in,out] ip0 ip header - * @param[out] p_proto protocol used for matching - * @param[out] p_value address and port after NAT translation - * @param[out] p_dont_translate if packet should not be translated - * @param d optional parameter - * @param e optional parameter - */ -u32 +static_always_inline u32 nat44_ei_icmp_match_in2out_slow (vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, ip4_address_t *addr, u16 *port, @@ -605,10 +655,8 @@ out: *p_s0 = s0; return next0; } -#endif -#ifndef CLIB_MARCH_VARIANT -u32 +static_always_inline u32 nat44_ei_icmp_match_in2out_fast (vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, ip4_header_t *ip0, ip4_address_t *addr, u16 *port, @@ -674,16 +722,135 @@ nat44_ei_icmp_match_in2out_fast (vlib_node_runtime_t *node, u32 thread_index, out: return next0; } -#endif -u32 nat44_ei_icmp_in2out (vlib_buffer_t *b0, ip4_header_t *ip0, - icmp46_header_t *icmp0, u32 sw_if_index0, - u32 rx_fib_index0, vlib_node_runtime_t *node, - u32 next0, u32 thread_index, - nat44_ei_session_t **p_s0); +static_always_inline u32 +nat44_ei_icmp_hairpinning (nat44_ei_main_t *nm, vlib_buffer_t *b0, + u32 thread_index, ip4_header_t *ip0, + icmp46_header_t *icmp0, u32 *required_thread_index) +{ + clib_bihash_kv_8_8_t kv0, value0; + u32 old_dst_addr0, new_dst_addr0; + u32 old_addr0, new_addr0; + u16 old_port0, new_port0; + u16 old_checksum0, new_checksum0; + u32 si, ti = 0; + ip_csum_t sum0; + nat44_ei_session_t *s0; + nat44_ei_static_mapping_t *m0; -#ifndef CLIB_MARCH_VARIANT -u32 + if (icmp_type_is_error_message ( + vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags)) + { + ip4_header_t *inner_ip0 = 0; + tcp_udp_header_t *l4_header = 0; + + inner_ip0 = (ip4_header_t *) ((icmp_echo_header_t *) (icmp0 + 1) + 1); + l4_header = ip4_next_header (inner_ip0); + u32 protocol = ip_proto_to_nat_proto (inner_ip0->protocol); + + if (protocol != NAT_PROTOCOL_TCP && protocol != NAT_PROTOCOL_UDP) + return 1; + + init_nat_k (&kv0, ip0->dst_address, l4_header->src_port, + nm->outside_fib_index, protocol); + if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0)) + return 1; + ti = nat_value_get_thread_index (&value0); + if (ti != thread_index) + { + *required_thread_index = ti; + return 1; + } + si = nat_value_get_session_index (&value0); + s0 = pool_elt_at_index (nm->per_thread_data[ti].sessions, si); + new_dst_addr0 = s0->in2out.addr.as_u32; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; + + /* update inner source IP address */ + old_addr0 = inner_ip0->src_address.as_u32; + inner_ip0->src_address.as_u32 = new_dst_addr0; + new_addr0 = inner_ip0->src_address.as_u32; + sum0 = icmp0->checksum; + sum0 = + ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, src_address); + icmp0->checksum = ip_csum_fold (sum0); + + /* update inner IP header checksum */ + old_checksum0 = inner_ip0->checksum; + sum0 = inner_ip0->checksum; + sum0 = + ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, src_address); + inner_ip0->checksum = ip_csum_fold (sum0); + new_checksum0 = inner_ip0->checksum; + sum0 = icmp0->checksum; + sum0 = ip_csum_update (sum0, old_checksum0, new_checksum0, ip4_header_t, + checksum); + icmp0->checksum = ip_csum_fold (sum0); + + /* update inner source port */ + old_port0 = l4_header->src_port; + l4_header->src_port = s0->in2out.port; + new_port0 = l4_header->src_port; + sum0 = icmp0->checksum; + sum0 = ip_csum_update (sum0, old_port0, new_port0, tcp_udp_header_t, + src_port); + icmp0->checksum = ip_csum_fold (sum0); + } + else + { + init_nat_k (&kv0, ip0->dst_address, 0, nm->outside_fib_index, 0); + if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv0, + &value0)) + { + icmp_echo_header_t *echo0 = (icmp_echo_header_t *) (icmp0 + 1); + u16 icmp_id0 = echo0->identifier; + init_nat_k (&kv0, ip0->dst_address, icmp_id0, nm->outside_fib_index, + NAT_PROTOCOL_ICMP); + int rv = clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0); + if (!rv) + { + ti = nat_value_get_thread_index (&value0); + if (ti != thread_index) + { + *required_thread_index = ti; + return 1; + } + si = nat_value_get_session_index (&value0); + s0 = pool_elt_at_index (nm->per_thread_data[ti].sessions, si); + new_dst_addr0 = s0->in2out.addr.as_u32; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; + echo0->identifier = s0->in2out.port; + sum0 = icmp0->checksum; + sum0 = ip_csum_update (sum0, icmp_id0, s0->in2out.port, + icmp_echo_header_t, identifier); + icmp0->checksum = ip_csum_fold (sum0); + goto change_addr; + } + + return 1; + } + + m0 = pool_elt_at_index (nm->static_mappings, value0.value); + + new_dst_addr0 = m0->local_addr.as_u32; + if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0) + vnet_buffer (b0)->sw_if_index[VLIB_TX] = m0->fib_index; + } +change_addr: + /* Destination is behind the same NAT, use internal address and port */ + if (new_dst_addr0) + { + old_dst_addr0 = ip0->dst_address.as_u32; + ip0->dst_address.as_u32 = new_dst_addr0; + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, ip4_header_t, + dst_address); + ip0->checksum = ip_csum_fold (sum0); + } + return 0; +} + +static_always_inline u32 nat44_ei_icmp_in2out (vlib_buffer_t *b0, ip4_header_t *ip0, icmp46_header_t *icmp0, u32 sw_if_index0, u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0, @@ -692,7 +859,7 @@ nat44_ei_icmp_in2out (vlib_buffer_t *b0, ip4_header_t *ip0, nat44_ei_main_t *nm = &nat44_ei_main; vlib_main_t *vm = vlib_get_main (); ip4_address_t addr; - u16 port; + u16 port = 0; u32 fib_index; nat_protocol_t proto; icmp_echo_header_t *echo0, *inner_echo0 = 0; @@ -854,7 +1021,6 @@ nat44_ei_icmp_in2out (vlib_buffer_t *b0, ip4_header_t *ip0, out: return next0; } -#endif static_always_inline u32 nat44_ei_icmp_in2out_slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0, @@ -879,6 +1045,31 @@ nat44_ei_icmp_in2out_slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0, return next0; } +static_always_inline void +nat44_ei_hairpinning_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b, + ip4_header_t *ip) +{ + clib_bihash_kv_8_8_t kv, value; + nat44_ei_static_mapping_t *m; + u32 old_addr, new_addr; + ip_csum_t sum; + + init_nat_k (&kv, ip->dst_address, 0, 0, 0); + if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value)) + return; + + m = pool_elt_at_index (nm->static_mappings, value.value); + + old_addr = ip->dst_address.as_u32; + new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32; + sum = ip->checksum; + sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address); + ip->checksum = ip_csum_fold (sum); + + if (vnet_buffer (b)->sw_if_index[VLIB_TX] == ~0) + vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index; +} + static int nat_in2out_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b, ip4_header_t *ip, u32 rx_fib_index) @@ -911,7 +1102,174 @@ nat_in2out_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b, return 0; } -static inline uword +static_always_inline int +nat44_ei_hairpinning (vlib_main_t *vm, vlib_node_runtime_t *node, + nat44_ei_main_t *nm, u32 thread_index, vlib_buffer_t *b0, + ip4_header_t *ip0, udp_header_t *udp0, + tcp_header_t *tcp0, u32 proto0, int do_trace, + u32 *required_thread_index) +{ + nat44_ei_session_t *s0 = NULL; + clib_bihash_kv_8_8_t kv0, value0; + ip_csum_t sum0; + u32 new_dst_addr0 = 0, old_dst_addr0, si = ~0; + u16 new_dst_port0 = ~0, old_dst_port0; + int rv; + ip4_address_t sm0_addr; + u16 sm0_port; + u32 sm0_fib_index; + u32 old_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + + /* Check if destination is static mappings */ + if (!nat44_ei_static_mapping_match ( + ip0->dst_address, udp0->dst_port, nm->outside_fib_index, proto0, + &sm0_addr, &sm0_port, &sm0_fib_index, 1 /* by external */, 0, 0)) + { + new_dst_addr0 = sm0_addr.as_u32; + new_dst_port0 = sm0_port; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0_fib_index; + } + /* or active session */ + else + { + init_nat_k (&kv0, ip0->dst_address, udp0->dst_port, + nm->outside_fib_index, proto0); + rv = clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0); + if (rv) + { + rv = 0; + goto trace; + } + + if (thread_index != nat_value_get_thread_index (&value0)) + { + *required_thread_index = nat_value_get_thread_index (&value0); + return 0; + } + + si = nat_value_get_session_index (&value0); + s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions, si); + new_dst_addr0 = s0->in2out.addr.as_u32; + new_dst_port0 = s0->in2out.port; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index; + } + + /* Check if anything has changed and if not, then return 0. This + helps avoid infinite loop, repeating the three nodes + nat44-hairpinning-->ip4-lookup-->ip4-local, in case nothing has + changed. */ + old_dst_addr0 = ip0->dst_address.as_u32; + old_dst_port0 = tcp0->dst; + if (new_dst_addr0 == old_dst_addr0 && new_dst_port0 == old_dst_port0 && + vnet_buffer (b0)->sw_if_index[VLIB_TX] == old_sw_if_index) + return 0; + + /* Destination is behind the same NAT, use internal address and port */ + if (new_dst_addr0) + { + old_dst_addr0 = ip0->dst_address.as_u32; + ip0->dst_address.as_u32 = new_dst_addr0; + sum0 = ip0->checksum; + sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, ip4_header_t, + dst_address); + ip0->checksum = ip_csum_fold (sum0); + + old_dst_port0 = tcp0->dst; + if (PREDICT_TRUE (new_dst_port0 != old_dst_port0)) + { + if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP)) + { + tcp0->dst = new_dst_port0; + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, + ip4_header_t, dst_address); + sum0 = ip_csum_update (sum0, old_dst_port0, new_dst_port0, + ip4_header_t /* cheat */, length); + tcp0->checksum = ip_csum_fold (sum0); + } + else + { + udp0->dst_port = new_dst_port0; + udp0->checksum = 0; + } + } + else + { + if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP)) + { + sum0 = tcp0->checksum; + sum0 = ip_csum_update (sum0, old_dst_addr0, new_dst_addr0, + ip4_header_t, dst_address); + tcp0->checksum = ip_csum_fold (sum0); + } + } + rv = 1; + goto trace; + } + rv = 0; +trace: + if (do_trace && PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && + (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + nat44_ei_hairpin_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->addr.as_u32 = new_dst_addr0; + t->port = new_dst_port0; + t->fib_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + if (s0) + { + t->session_index = si; + } + else + { + t->session_index = ~0; + } + } + return rv; +} + +static_always_inline uword +nat44_ei_hairpinning_handoff_fn_inline (vlib_main_t *vm, + vlib_node_runtime_t *node, + vlib_frame_t *frame, u32 fq_index) +{ + vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; + u32 n_enq, n_left_from, *from; + u16 thread_indices[VLIB_FRAME_SIZE], *ti; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + vlib_get_buffers (vm, from, bufs, n_left_from); + + b = bufs; + ti = thread_indices; + + while (n_left_from > 0) + { + ti[0] = vnet_buffer (b[0])->snat.required_thread_index; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && + (b[0]->flags & VLIB_BUFFER_IS_TRACED))) + { + nat44_ei_hairpinning_handoff_trace_t *t = + vlib_add_trace (vm, node, b[0], sizeof (*t)); + t->next_worker_index = ti[0]; + } + + n_left_from -= 1; + ti += 1; + b += 1; + } + n_enq = vlib_buffer_enqueue_to_thread (vm, node, fq_index, from, + thread_indices, frame->n_vectors, 1); + + if (n_enq < frame->n_vectors) + vlib_node_increment_counter ( + vm, node->node_index, NAT44_EI_HAIRPINNING_HANDOFF_ERROR_CONGESTION_DROP, + frame->n_vectors - n_enq); + return frame->n_vectors; +} + +static_always_inline uword nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_slow_path, int is_output_feature) @@ -987,7 +1345,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node, next0 = next1 = NAT44_EI_IN2OUT_NEXT_LOOKUP; - if (PREDICT_FALSE (ip0->ttl == 1)) + if (PREDICT_FALSE (!is_output_feature && ip0->ttl == 1)) { vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, @@ -1206,7 +1564,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node, rx_fib_index1 = vec_elt (nm->ip4_main->fib_index_by_sw_if_index, rx_sw_if_index1); - if (PREDICT_FALSE (ip1->ttl == 1)) + if (PREDICT_FALSE (!is_output_feature && ip1->ttl == 1)) { vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0; icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded, @@ -1453,7 +1811,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node, rx_fib_index0 = vec_elt (nm->ip4_main->fib_index_by_sw_if_index, rx_sw_if_index0); - if (PREDICT_FALSE (ip0->ttl == 1)) + if (PREDICT_FALSE (!is_output_feature && ip0->ttl == 1)) { vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, @@ -1667,128 +2025,10 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node, return frame->n_vectors; } -VLIB_NODE_FN (nat44_ei_in2out_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - return nat44_ei_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */, - 0); -} - -VLIB_REGISTER_NODE (nat44_ei_in2out_node) = { - .name = "nat44-ei-in2out", - .vector_size = sizeof (u32), - .format_trace = format_nat44_ei_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), - .error_strings = nat44_ei_in2out_error_strings, - - .runtime_data_bytes = sizeof (nat44_ei_runtime_t), - - .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop", - [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath", - [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup", - }, -}; - -VLIB_NODE_FN (nat44_ei_in2out_output_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - return nat44_ei_in2out_node_fn_inline (vm, node, frame, 0 /* is_slow_path */, - 1); -} - -VLIB_REGISTER_NODE (nat44_ei_in2out_output_node) = { - .name = "nat44-ei-in2out-output", - .vector_size = sizeof (u32), - .format_trace = format_nat44_ei_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), - .error_strings = nat44_ei_in2out_error_strings, - - .runtime_data_bytes = sizeof (nat44_ei_runtime_t), - - .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop", - [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "interface-output", - [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-output-slowpath", - [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-interface-output", - }, -}; - -VLIB_NODE_FN (nat44_ei_in2out_slowpath_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - return nat44_ei_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */, - 0); -} - -VLIB_REGISTER_NODE (nat44_ei_in2out_slowpath_node) = { - .name = "nat44-ei-in2out-slowpath", - .vector_size = sizeof (u32), - .format_trace = format_nat44_ei_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), - .error_strings = nat44_ei_in2out_error_strings, - - .runtime_data_bytes = sizeof (nat44_ei_runtime_t), - - .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop", - [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath", - [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup", - }, -}; - -VLIB_NODE_FN (nat44_ei_in2out_output_slowpath_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - return nat44_ei_in2out_node_fn_inline (vm, node, frame, 1 /* is_slow_path */, - 1); -} - -VLIB_REGISTER_NODE (nat44_ei_in2out_output_slowpath_node) = { - .name = "nat44-ei-in2out-output-slowpath", - .vector_size = sizeof (u32), - .format_trace = format_nat44_ei_in2out_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), - .error_strings = nat44_ei_in2out_error_strings, - - .runtime_data_bytes = sizeof (nat44_ei_runtime_t), - - .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop", - [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "interface-output", - [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-output-slowpath", - [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-interface-output", - }, -}; - -VLIB_NODE_FN (nat44_ei_in2out_fast_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +static_always_inline uword +nat44_ei_in2out_hairpinning_finish_inline (vlib_main_t *vm, + vlib_node_runtime_t *node, + vlib_frame_t *frame) { u32 n_left_from, *from, *to_next; u32 thread_index = vm->thread_index; @@ -1813,20 +2053,12 @@ VLIB_NODE_FN (nat44_ei_in2out_fast_node) u32 next0; u32 sw_if_index0; ip4_header_t *ip0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 old_port0, new_port0; udp_header_t *udp0; tcp_header_t *tcp0; icmp46_header_t *icmp0; u32 proto0; - u32 rx_fib_index0; - ip4_address_t sm0_addr; - u16 sm0_port; - u32 sm0_fib_index; u32 required_thread_index = thread_index; - /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; to_next[0] = bi0; from += 1; @@ -1835,7 +2067,7 @@ VLIB_NODE_FN (nat44_ei_in2out_fast_node) n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); - next0 = NAT44_EI_IN2OUT_NEXT_LOOKUP; + next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP; ip0 = vlib_buffer_get_current (b0); udp0 = ip4_next_header (ip0); @@ -1843,117 +2075,36 @@ VLIB_NODE_FN (nat44_ei_in2out_fast_node) icmp0 = (icmp46_header_t *) udp0; sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = - ip4_fib_table_get_index_for_sw_if_index (sw_if_index0); - - if (PREDICT_FALSE (ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = NAT44_EI_IN2OUT_NEXT_ICMP_ERROR; - goto trace0; - } - proto0 = ip_proto_to_nat_proto (ip0->protocol); - if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER)) - goto trace0; - - if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP)) - { - next0 = nat44_ei_icmp_in2out (b0, ip0, icmp0, sw_if_index0, - rx_fib_index0, node, next0, ~0, 0); - goto trace0; - } - - if (nat44_ei_static_mapping_match ( - ip0->src_address, udp0->src_port, rx_fib_index0, proto0, - &sm0_addr, &sm0_port, &sm0_fib_index, 0, 0, 0)) - { - b0->error = node->errors[NAT44_EI_IN2OUT_ERROR_NO_TRANSLATION]; - next0 = NAT44_EI_IN2OUT_NEXT_DROP; - goto trace0; - } - - new_addr0 = sm0_addr.as_u32; - new_port0 = sm0_port; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm0_fib_index; - old_addr0 = ip0->src_address.as_u32; - ip0->src_address.as_u32 = new_addr0; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - src_address /* changed member */ ); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_FALSE (new_port0 != udp0->dst_port)) - { - old_port0 = udp0->src_port; - udp0->src_port = new_port0; - - if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP)) - { - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */ ); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */ , - length /* changed member */ ); - mss_clamping (nm->mss_clamping, tcp0, &sum0); - tcp0->checksum = ip_csum_fold (sum0); - } - else if (udp0->checksum) - { - sum0 = udp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */ ); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */ , - length /* changed member */ ); - udp0->checksum = ip_csum_fold (sum0); - } - } - else + switch (proto0) { - if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP)) - { - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */ ); - mss_clamping (nm->mss_clamping, tcp0, &sum0); - tcp0->checksum = ip_csum_fold (sum0); - } - else if (udp0->checksum) - { - sum0 = udp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */ ); - udp0->checksum = ip_csum_fold (sum0); - } + case NAT_PROTOCOL_TCP: + // fallthrough + case NAT_PROTOCOL_UDP: + is_hairpinning = nat44_ei_hairpinning ( + vm, node, nm, thread_index, b0, ip0, udp0, tcp0, proto0, + 0 /* do_trace */, &required_thread_index); + break; + case NAT_PROTOCOL_ICMP: + is_hairpinning = (0 == nat44_ei_icmp_hairpinning ( + nm, b0, thread_index, ip0, icmp0, + &required_thread_index)); + break; + case NAT_PROTOCOL_OTHER: + // this should never happen + next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP; + break; } - /* Hairpinning */ - is_hairpinning = nat44_ei_hairpinning ( - vm, node, nm, thread_index, b0, ip0, udp0, tcp0, proto0, - 0 /* do_trace */, &required_thread_index); - if (thread_index != required_thread_index) { - vnet_buffer (b0)->snat.required_thread_index = - required_thread_index; - next0 = NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF; + // but we already did a handoff ... + next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP; } - trace0: - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && + (b0->flags & VLIB_BUFFER_IS_TRACED))) { nat44_ei_in2out_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); @@ -1962,18 +2113,15 @@ VLIB_NODE_FN (nat44_ei_in2out_fast_node) t->is_hairpinning = is_hairpinning; } - if (next0 != NAT44_EI_IN2OUT_NEXT_DROP) + if (next0 != NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP) { - vlib_increment_simple_counter ( &nm->counters.fastpath.in2out.other, sw_if_index0, vm->thread_index, 1); } - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, bi0, next0); } vlib_put_next_frame (vm, node, next_index, n_left_to_next); @@ -1982,83 +2130,16 @@ VLIB_NODE_FN (nat44_ei_in2out_fast_node) return frame->n_vectors; } -VLIB_REGISTER_NODE (nat44_ei_in2out_fast_node) = { - .name = "nat44-ei-in2out-fast", - .vector_size = sizeof (u32), - .format_trace = format_nat44_ei_in2out_fast_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), - .error_strings = nat44_ei_in2out_error_strings, - - .runtime_data_bytes = sizeof (nat44_ei_runtime_t), - - .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop", - [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", - [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath", - [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", - [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup", - }, -}; - -VLIB_NODE_FN (nat44_ei_in2out_hairpinning_handoff_ip4_lookup_node) +VLIB_NODE_FN (nat44_ei_hairpinning_node) (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) { - return nat44_ei_hairpinning_handoff_fn_inline ( - vm, node, frame, - nat44_ei_main.in2out_hairpinning_finish_ip4_lookup_node_fq_index); -} - -VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_handoff_ip4_lookup_node) = { - .name = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup", - .vector_size = sizeof (u32), - .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings), - .error_strings = nat44_ei_hairpinning_handoff_error_strings, - .format_trace = format_nat44_ei_hairpinning_handoff_trace, - - .n_next_nodes = 1, - - .next_nodes = { - [0] = "error-drop", - }, -}; - -VLIB_NODE_FN (nat44_ei_in2out_hairpinning_handoff_interface_output_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - return nat44_ei_hairpinning_handoff_fn_inline ( - vm, node, frame, - nat44_ei_main.in2out_hairpinning_finish_interface_output_node_fq_index); -} - -VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_handoff_interface_output_node) = { - .name = "nat44-ei-in2out-hairpinning-handoff-interface-output", - .vector_size = sizeof (u32), - .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings), - .error_strings = nat44_ei_hairpinning_handoff_error_strings, - .format_trace = format_nat44_ei_hairpinning_handoff_trace, - - .n_next_nodes = 1, - - .next_nodes = { - [0] = "error-drop", - }, -}; - -static_always_inline int -nat44_ei_in2out_hairpinning_finish_inline (vlib_main_t *vm, - vlib_node_runtime_t *node, - vlib_frame_t *frame) -{ u32 n_left_from, *from, *to_next; u32 thread_index = vm->thread_index; - nat44_ei_in2out_next_t next_index; + nat44_ei_hairpin_next_t next_index; nat44_ei_main_t *nm = &nat44_ei_main; - int is_hairpinning = 0; + vnet_feature_main_t *fm = &feature_main; + u8 arc_index = vnet_feat_arc_ip4_local.feature_arc_index; + vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc_index]; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -2075,15 +2156,13 @@ nat44_ei_in2out_hairpinning_finish_inline (vlib_main_t *vm, u32 bi0; vlib_buffer_t *b0; u32 next0; - u32 sw_if_index0; ip4_header_t *ip0; + u32 proto0; udp_header_t *udp0; tcp_header_t *tcp0; - icmp46_header_t *icmp0; - u32 proto0; + u32 sw_if_index0; u32 required_thread_index = thread_index; - /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; to_next[0] = bi0; from += 1; @@ -2092,60 +2171,39 @@ nat44_ei_in2out_hairpinning_finish_inline (vlib_main_t *vm, n_left_to_next -= 1; b0 = vlib_get_buffer (vm, bi0); - next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP; - ip0 = vlib_buffer_get_current (b0); udp0 = ip4_next_header (ip0); tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + proto0 = ip_proto_to_nat_proto (ip0->protocol); + int next0_resolved = 0; - switch (proto0) + if (nat44_ei_hairpinning (vm, node, nm, thread_index, b0, ip0, udp0, + tcp0, proto0, 1, &required_thread_index)) { - case NAT_PROTOCOL_TCP: - // fallthrough - case NAT_PROTOCOL_UDP: - is_hairpinning = nat44_ei_hairpinning ( - vm, node, nm, thread_index, b0, ip0, udp0, tcp0, proto0, - 0 /* do_trace */, &required_thread_index); - break; - case NAT_PROTOCOL_ICMP: - is_hairpinning = (0 == nat44_ei_icmp_hairpinning ( - nm, b0, thread_index, ip0, icmp0, - &required_thread_index)); - break; - case NAT_PROTOCOL_OTHER: - // this should never happen - next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP; - break; + next0 = NAT44_EI_HAIRPIN_NEXT_LOOKUP; + next0_resolved = 1; } if (thread_index != required_thread_index) { - // but we already did a handoff ... - next0 = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP; + vnet_buffer (b0)->snat.required_thread_index = + required_thread_index; + next0 = NAT44_EI_HAIRPIN_NEXT_HANDOFF; + next0_resolved = 1; } - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && - (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - nat44_ei_in2out_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - t->is_hairpinning = is_hairpinning; - } + if (!next0_resolved) + vnet_get_config_data (&cm->config_main, &b0->current_config_index, + &next0, 0); - if (next0 != NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP) + if (next0 != NAT44_EI_HAIRPIN_NEXT_DROP) { vlib_increment_simple_counter ( - &nm->counters.fastpath.in2out.other, sw_if_index0, - vm->thread_index, 1); + &nm->counters.hairpinning, vm->thread_index, sw_if_index0, 1); } - /* verify speculative enqueue, maybe switch current next frame */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); } @@ -2156,58 +2214,216 @@ nat44_ei_in2out_hairpinning_finish_inline (vlib_main_t *vm, return frame->n_vectors; } +VLIB_NODE_FN (nat44_ei_in2out_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return nat44_ei_in2out_node_fn_inline (vm, node, frame, 0, 0); +} + +VLIB_NODE_FN (nat44_ei_in2out_output_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return nat44_ei_in2out_node_fn_inline (vm, node, frame, 0, 1); +} + +VLIB_NODE_FN (nat44_ei_in2out_slowpath_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return nat44_ei_in2out_node_fn_inline (vm, node, frame, 1, 0); +} + +VLIB_NODE_FN (nat44_ei_in2out_output_slowpath_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return nat44_ei_in2out_node_fn_inline (vm, node, frame, 1, 1); +} + +VLIB_NODE_FN (nat44_ei_in2out_hairpinning_handoff_ip4_lookup_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return nat44_ei_hairpinning_handoff_fn_inline ( + vm, node, frame, + nat44_ei_main.in2out_hairpinning_finish_ip4_lookup_node_fq_index); +} + +VLIB_NODE_FN (nat44_ei_in2out_hairpinning_handoff_interface_output_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return nat44_ei_hairpinning_handoff_fn_inline ( + vm, node, frame, + nat44_ei_main.in2out_hairpinning_finish_interface_output_node_fq_index); +} + VLIB_NODE_FN (nat44_ei_in2out_hairpinning_finish_ip4_lookup_node) (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) { return nat44_ei_in2out_hairpinning_finish_inline (vm, node, frame); } -VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_finish_ip4_lookup_node) = { - .name = "nat44-ei-in2out-hairpinning-finish-ip4-lookup", +VLIB_NODE_FN (nat44_ei_in2out_hairpinning_finish_interface_output_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return nat44_ei_in2out_hairpinning_finish_inline (vm, node, frame); +} + +VLIB_NODE_FN (nat44_ei_hairpinning_handoff_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return nat44_ei_hairpinning_handoff_fn_inline ( + vm, node, frame, nat44_ei_main.hairpinning_fq_index); +} + +VLIB_REGISTER_NODE (nat44_ei_in2out_node) = { + .name = "nat44-ei-in2out", .vector_size = sizeof (u32), - .format_trace = format_nat44_ei_in2out_fast_trace, + .format_trace = format_nat44_ei_in2out_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), + .error_strings = nat44_ei_in2out_error_strings, + .runtime_data_bytes = sizeof (nat44_ei_runtime_t), + .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT, + .next_nodes = { + [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop", + [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", + [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath", + [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", + [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup", + }, +}; + +VLIB_REGISTER_NODE (nat44_ei_in2out_output_node) = { + .name = "nat44-ei-in2out-output", + .vector_size = sizeof (u32), + .format_trace = format_nat44_ei_in2out_trace, .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), + .error_strings = nat44_ei_in2out_error_strings, + .runtime_data_bytes = sizeof (nat44_ei_runtime_t), + .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT, + .next_nodes = { + [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop", + [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "interface-output", + [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-output-slowpath", + [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", + [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-interface-output", + }, +}; +VLIB_REGISTER_NODE (nat44_ei_in2out_slowpath_node) = { + .name = "nat44-ei-in2out-slowpath", + .vector_size = sizeof (u32), + .format_trace = format_nat44_ei_in2out_trace, + .type = VLIB_NODE_TYPE_INTERNAL, .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), .error_strings = nat44_ei_in2out_error_strings, + .runtime_data_bytes = sizeof (nat44_ei_runtime_t), + .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT, + .next_nodes = { + [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop", + [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "ip4-lookup", + [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-slowpath", + [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", + [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup", + }, +}; +VLIB_REGISTER_NODE (nat44_ei_in2out_output_slowpath_node) = { + .name = "nat44-ei-in2out-output-slowpath", + .vector_size = sizeof (u32), + .format_trace = format_nat44_ei_in2out_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), + .error_strings = nat44_ei_in2out_error_strings, .runtime_data_bytes = sizeof (nat44_ei_runtime_t), + .n_next_nodes = NAT44_EI_IN2OUT_N_NEXT, + .next_nodes = { + [NAT44_EI_IN2OUT_NEXT_DROP] = "error-drop", + [NAT44_EI_IN2OUT_NEXT_LOOKUP] = "interface-output", + [NAT44_EI_IN2OUT_NEXT_SLOW_PATH] = "nat44-ei-in2out-output-slowpath", + [NAT44_EI_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error", + [NAT44_EI_IN2OUT_NEXT_HAIRPINNING_HANDOFF] = "nat44-ei-in2out-hairpinning-handoff-interface-output", + }, +}; - .n_next_nodes = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT, +VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_handoff_ip4_lookup_node) = { + .name = "nat44-ei-in2out-hairpinning-handoff-ip4-lookup", + .vector_size = sizeof (u32), + .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings), + .error_strings = nat44_ei_hairpinning_handoff_error_strings, + .format_trace = format_nat44_ei_hairpinning_handoff_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "error-drop", + }, +}; - /* edit / add dispositions here */ +VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_handoff_interface_output_node) = { + .name = "nat44-ei-in2out-hairpinning-handoff-interface-output", + .vector_size = sizeof (u32), + .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings), + .error_strings = nat44_ei_hairpinning_handoff_error_strings, + .format_trace = format_nat44_ei_hairpinning_handoff_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "error-drop", + }, +}; + +VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_finish_ip4_lookup_node) = { + .name = "nat44-ei-in2out-hairpinning-finish-ip4-lookup", + .vector_size = sizeof (u32), + .format_trace = format_nat44_ei_in2out_fast_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), + .error_strings = nat44_ei_in2out_error_strings, + .runtime_data_bytes = sizeof (nat44_ei_runtime_t), + .n_next_nodes = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT, .next_nodes = { [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP] = "error-drop", [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP] = "ip4-lookup", }, }; -VLIB_NODE_FN (nat44_ei_in2out_hairpinning_finish_interface_output_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - return nat44_ei_in2out_hairpinning_finish_inline (vm, node, frame); -} - VLIB_REGISTER_NODE (nat44_ei_in2out_hairpinning_finish_interface_output_node) = { .name = "nat44-ei-in2out-hairpinning-finish-interface-output", .vector_size = sizeof (u32), .format_trace = format_nat44_ei_in2out_fast_trace, .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(nat44_ei_in2out_error_strings), .error_strings = nat44_ei_in2out_error_strings, - .runtime_data_bytes = sizeof (nat44_ei_runtime_t), - .n_next_nodes = NAT44_EI_IN2OUT_HAIRPINNING_FINISH_N_NEXT, - - /* edit / add dispositions here */ .next_nodes = { [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_DROP] = "error-drop", [NAT44_EI_IN2OUT_HAIRPINNING_FINISH_NEXT_LOOKUP] = "interface-output", }, }; +VLIB_REGISTER_NODE (nat44_ei_hairpinning_handoff_node) = { + .name = "nat44-ei-hairpinning-handoff", + .vector_size = sizeof (u32), + .n_errors = ARRAY_LEN(nat44_ei_hairpinning_handoff_error_strings), + .error_strings = nat44_ei_hairpinning_handoff_error_strings, + .format_trace = format_nat44_ei_hairpinning_handoff_trace, + .n_next_nodes = 1, + .next_nodes = { + [0] = "error-drop", + }, +}; + +VLIB_REGISTER_NODE (nat44_ei_hairpinning_node) = { + .name = "nat44-ei-hairpinning", + .vector_size = sizeof (u32), + .type = VLIB_NODE_TYPE_INTERNAL, + .format_trace = format_nat44_ei_hairpin_trace, + .n_next_nodes = NAT44_EI_HAIRPIN_N_NEXT, + .next_nodes = { + [NAT44_EI_HAIRPIN_NEXT_DROP] = "error-drop", + [NAT44_EI_HAIRPIN_NEXT_LOOKUP] = "ip4-lookup", + [NAT44_EI_HAIRPIN_NEXT_HANDOFF] = "nat44-ei-hairpinning-handoff", + }, +}; + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/nat/nat44-ei/nat44_ei_out2in.c b/src/plugins/nat/nat44-ei/nat44_ei_out2in.c index 7858811fde5..5d91cb04f7c 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_out2in.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_out2in.c @@ -56,18 +56,6 @@ format_nat44_ei_out2in_trace (u8 *s, va_list *args) return s; } -static u8 * -format_nat44_ei_out2in_fast_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_ei_out2in_trace_t *t = va_arg (*args, nat44_ei_out2in_trace_t *); - - s = format (s, "NAT44_OUT2IN_FAST: sw_if_index %d, next index %d", - t->sw_if_index, t->next_index); - return s; -} - #define foreach_nat44_ei_out2in_error \ _ (UNSUPPORTED_PROTOCOL, "unsupported protocol") \ _ (OUT_OF_PORTS, "out of ports") \ @@ -1336,7 +1324,6 @@ VLIB_NODE_FN (nat44_ei_out2in_node) return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat44_ei_out2in_node) = { .name = "nat44-ei-out2in", .vector_size = sizeof (u32), @@ -1357,190 +1344,6 @@ VLIB_REGISTER_NODE (nat44_ei_out2in_node) = { [NAT44_EI_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", }, }; -/* *INDENT-ON* */ - -VLIB_NODE_FN (nat44_ei_out2in_fast_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) -{ - u32 n_left_from, *from; - nat44_ei_main_t *nm = &nat44_ei_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - - vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs; - u16 nexts[VLIB_FRAME_SIZE], *next = nexts; - vlib_get_buffers (vm, from, b, n_left_from); - while (n_left_from > 0) - { - vlib_buffer_t *b0; - u32 next0 = NAT44_EI_OUT2IN_NEXT_DROP; - u32 sw_if_index0; - ip4_header_t *ip0; - ip_csum_t sum0; - u32 new_addr0, old_addr0; - u16 new_port0, old_port0; - udp_header_t *udp0; - tcp_header_t *tcp0; - icmp46_header_t *icmp0; - u32 proto0; - u32 rx_fib_index0; - ip4_address_t sm_addr0; - u16 sm_port0; - u32 sm_fib_index0; - - b0 = *b; - b++; - - ip0 = vlib_buffer_get_current (b0); - udp0 = ip4_next_header (ip0); - tcp0 = (tcp_header_t *) udp0; - icmp0 = (icmp46_header_t *) udp0; - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0); - - vnet_feature_next (&next0, b0); - - if (PREDICT_FALSE (ip0->ttl == 1)) - { - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; - icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded, - ICMP4_time_exceeded_ttl_exceeded_in_transit, - 0); - next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR; - goto trace00; - } - - proto0 = ip_proto_to_nat_proto (ip0->protocol); - - if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER)) - goto trace00; - - if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP)) - { - next0 = nat44_ei_icmp_out2in (b0, ip0, icmp0, sw_if_index0, - rx_fib_index0, node, next0, ~0, 0); - goto trace00; - } - - if (nat44_ei_static_mapping_match (ip0->dst_address, udp0->dst_port, - rx_fib_index0, proto0, &sm_addr0, - &sm_port0, &sm_fib_index0, 1, 0, 0)) - { - b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION]; - goto trace00; - } - - new_addr0 = sm_addr0.as_u32; - new_port0 = sm_port0; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm_fib_index0; - old_addr0 = ip0->dst_address.as_u32; - ip0->dst_address.as_u32 = new_addr0; - - sum0 = ip0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, dst_address /* changed member */ ); - ip0->checksum = ip_csum_fold (sum0); - - if (PREDICT_FALSE (new_port0 != udp0->dst_port)) - { - old_port0 = udp0->dst_port; - udp0->dst_port = new_port0; - - if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP)) - { - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */ ); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */ , - length /* changed member */ ); - tcp0->checksum = ip_csum_fold (sum0); - } - else if (udp0->checksum) - { - sum0 = udp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */ ); - sum0 = ip_csum_update (sum0, old_port0, new_port0, - ip4_header_t /* cheat */ , - length /* changed member */ ); - udp0->checksum = ip_csum_fold (sum0); - } - } - else - { - if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP)) - { - sum0 = tcp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */ ); - tcp0->checksum = ip_csum_fold (sum0); - } - else if (udp0->checksum) - { - sum0 = udp0->checksum; - sum0 = ip_csum_update (sum0, old_addr0, new_addr0, - ip4_header_t, - dst_address /* changed member */ ); - udp0->checksum = ip_csum_fold (sum0); - } - } - - trace00: - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - nat44_ei_out2in_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - t->next_index = next0; - } - - if (next0 == NAT44_EI_OUT2IN_NEXT_DROP) - { - vlib_increment_simple_counter (&nm->counters.fastpath.out2in.drops, - vm->thread_index, sw_if_index0, 1); - } - - n_left_from--; - next[0] = next0; - next++; - } - - vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts, - frame->n_vectors); - - return frame->n_vectors; -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (nat44_ei_out2in_fast_node) = { - .name = "nat44-ei-out2in-fast", - .vector_size = sizeof (u32), - .format_trace = format_nat44_ei_out2in_fast_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(nat44_ei_out2in_error_strings), - .error_strings = nat44_ei_out2in_error_strings, - - .runtime_data_bytes = sizeof (nat44_ei_runtime_t), - - .n_next_nodes = NAT44_EI_OUT2IN_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [NAT44_EI_OUT2IN_NEXT_LOOKUP] = "ip4-lookup", - [NAT44_EI_OUT2IN_NEXT_DROP] = "error-drop", - [NAT44_EI_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error", - }, -}; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/nat64/nat64.c b/src/plugins/nat/nat64/nat64.c index 1c1cdfba3fb..950eea60e5e 100644 --- a/src/plugins/nat/nat64/nat64.c +++ b/src/plugins/nat/nat64/nat64.c @@ -26,7 +26,6 @@ nat64_main_t nat64_main; -/* *INDENT-OFF* */ /* Hook up input features */ VNET_FEATURE_INIT (nat64_in2out, static) = { .arc_name = "ip6-unicast", @@ -62,7 +61,6 @@ static u8 well_known_prefix[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -/* *INDENT-ON* */ #define nat_elog_str(_str) \ do \ @@ -135,6 +133,20 @@ nat64_get_worker_in2out (ip6_address_t * addr) return next_worker_index; } +static u32 +get_thread_idx_by_port (u16 e_port) +{ + nat64_main_t *nm = &nat64_main; + u32 thread_idx = nm->num_workers; + if (nm->num_workers > 1) + { + thread_idx = nm->first_worker_index + + nm->workers[(e_port - 1024) / nm->port_per_thread % + _vec_len (nm->workers)]; + } + return thread_idx; +} + u32 nat64_get_worker_out2in (vlib_buffer_t * b, ip4_header_t * ip) { @@ -157,14 +169,12 @@ nat64_get_worker_out2in (vlib_buffer_t * b, ip4_header_t * ip) clib_memset (&daddr, 0, sizeof (daddr)); daddr.ip4.as_u32 = ip->dst_address.as_u32; - /* *INDENT-OFF* */ vec_foreach (db, nm->db) { bibe = nat64_db_bib_entry_find (db, &daddr, 0, ip->protocol, 0, 0); if (bibe) return (u32) (db - nm->db); } - /* *INDENT-ON* */ return vlib_get_thread_index (); } @@ -202,7 +212,7 @@ nat64_get_worker_out2in (vlib_buffer_t * b, ip4_header_t * ip) /* worker by outside port (TCP/UDP) */ port = clib_net_to_host_u16 (port); if (port > 1024) - return nm->first_worker_index + ((port - 1024) / nm->port_per_thread); + return get_thread_idx_by_port (port); return vlib_get_thread_index (); } @@ -282,12 +292,10 @@ nat64_init (vlib_main_t * vm) for (i = 0; i < nm->num_workers; i++) bitmap = clib_bitmap_set (bitmap, i, 1); - /* *INDENT-OFF* */ clib_bitmap_foreach (i, bitmap) { vec_add1(nm->workers, i); } - /* *INDENT-ON* */ clib_bitmap_free (bitmap); @@ -323,7 +331,6 @@ nat64_init_hash (nat64_config_t c) vec_validate (nm->db, tm->n_vlib_mains - 1); - /* *INDENT-OFF* */ vec_foreach (db, nm->db) { if (nat64_db_init (db, c, nat64_free_out_addr_and_port)) @@ -332,7 +339,6 @@ nat64_init_hash (nat64_config_t c) rv = 1; } } - /* *INDENT-ON* */ return rv; } @@ -344,7 +350,6 @@ nat64_free_hash () nat64_db_t *db; int rv = 0; - /* *INDENT-OFF* */ vec_foreach (db, nm->db) { if (nat64_db_free (db)) @@ -353,7 +358,6 @@ nat64_free_hash () rv = 1; } } - /* *INDENT-ON* */ vec_free (nm->db); @@ -408,7 +412,6 @@ nat64_add_del_pool_addr (u32 thread_index, if (a->fib_index != ~0) fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP6, nm->fib_src_hi); /* Delete sessions using address */ - /* *INDENT-OFF* */ vec_foreach (db, nm->db) { nat64_db_free_out_addr (thread_index, db, &a->addr); @@ -417,12 +420,10 @@ nat64_add_del_pool_addr (u32 thread_index, vlib_set_simple_counter (&nm->total_sessions, db - nm->db, 0, db->st.st_entries_num); } - /* *INDENT-ON* */ vec_del1 (nm->addr_pool, i); } /* Add/del external address to FIB */ - /* *INDENT-OFF* */ pool_foreach (interface, nm->interfaces) { if (nat64_interface_is_inside(interface)) @@ -431,7 +432,6 @@ nat64_add_del_pool_addr (u32 thread_index, nat64_add_del_addr_to_fib (addr, 32, interface->sw_if_index, is_add); break; } - /* *INDENT-ON* */ return 0; } @@ -442,13 +442,11 @@ nat64_pool_addr_walk (nat64_pool_addr_walk_fn_t fn, void *ctx) nat64_main_t *nm = &nat64_main; nat64_address_t *a = 0; - /* *INDENT-OFF* */ vec_foreach (a, nm->addr_pool) { if (fn (a, ctx)) break; }; - /* *INDENT-ON* */ } int @@ -546,7 +544,6 @@ nat64_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add) // TODO: is enabled ? we can't signal if it is not /* Check if interface already exists */ - /* *INDENT-OFF* */ pool_foreach (i, nm->interfaces) { if (i->sw_if_index == sw_if_index) @@ -555,7 +552,6 @@ nat64_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add) break; } } - /* *INDENT-ON* */ if (is_add) { @@ -596,10 +592,8 @@ nat64_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add) if (!is_inside) { - /* *INDENT-OFF* */ vec_foreach (ap, nm->addr_pool) nat64_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, is_add); - /* *INDENT-ON* */ } if (nm->num_workers > 1) @@ -641,13 +635,11 @@ nat64_interfaces_walk (nat64_interface_walk_fn_t fn, void *ctx) nat64_main_t *nm = &nat64_main; nat64_interface_t *i = 0; - /* *INDENT-OFF* */ pool_foreach (i, nm->interfaces) { if (fn (i, ctx)) break; } - /* *INDENT-ON* */ } // TODO: plugin independent @@ -822,7 +814,6 @@ nat64_static_bib_worker_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, nat64_db_bib_entry_t *bibe; ip46_address_t addr; - /* *INDENT-OFF* */ pool_foreach (static_bib, nm->static_bibs) { if ((static_bib->thread_index != thread_index) || (static_bib->done)) @@ -859,21 +850,18 @@ nat64_static_bib_worker_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, static_bib->done = 1; } - /* *INDENT-ON* */ return 0; } static vlib_node_registration_t nat64_static_bib_worker_node; -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat64_static_bib_worker_node, static) = { .function = nat64_static_bib_worker_fn, .type = VLIB_NODE_TYPE_INPUT, .state = VLIB_NODE_STATE_INTERRUPT, .name = "nat64-static-bib-worker", }; -/* *INDENT-ON* */ int nat64_add_del_static_bib_entry (ip6_address_t * in_addr, @@ -916,7 +904,7 @@ nat64_add_del_static_bib_entry (ip6_address_t * in_addr, /* outside port must be assigned to same thread as internall address */ if ((out_port > 1024) && (nm->num_workers > 1)) { - if (thread_index != ((out_port - 1024) / nm->port_per_thread)) + if (thread_index != get_thread_idx_by_port (out_port)) return VNET_API_ERROR_INVALID_VALUE_2; } @@ -977,7 +965,6 @@ nat64_add_del_static_bib_entry (ip6_address_t * in_addr, if (nm->num_workers) { - /* *INDENT-OFF* */ pool_foreach (static_bib, nm->static_bibs) { if (static_bib->done) @@ -985,7 +972,6 @@ nat64_add_del_static_bib_entry (ip6_address_t * in_addr, } vec_foreach (index, to_be_free) pool_put_index (nm->static_bibs, index[0]); - /* *INDENT-ON* */ vec_free (to_be_free); pool_get (nm->static_bibs, static_bib); static_bib->in_addr.as_u64[0] = in_addr->as_u64[0]; @@ -1258,13 +1244,11 @@ nat64_prefix_walk (nat64_prefix_walk_fn_t fn, void *ctx) nat64_main_t *nm = &nat64_main; nat64_prefix_t *p = 0; - /* *INDENT-OFF* */ vec_foreach (p, nm->pref64) { if (fn (p, ctx)) break; }; - /* *INDENT-ON* */ } void @@ -1273,7 +1257,6 @@ nat64_compose_ip6 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index) nat64_main_t *nm = &nat64_main; nat64_prefix_t *p, *gp = 0, *prefix = 0; - /* *INDENT-OFF* */ vec_foreach (p, nm->pref64) { if (p->fib_index == fib_index) @@ -1285,7 +1268,6 @@ nat64_compose_ip6 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index) if (p->fib_index == 0) gp = p; }; - /* *INDENT-ON* */ if (!prefix) prefix = gp; @@ -1344,7 +1326,6 @@ nat64_extract_ip4 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index) nat64_prefix_t *p, *gp = 0; u8 plen = 0; - /* *INDENT-OFF* */ vec_foreach (p, nm->pref64) { if (p->fib_index == fib_index) @@ -1356,7 +1337,6 @@ nat64_extract_ip4 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index) if (p->vrf_id == 0) gp = p; }; - /* *INDENT-ON* */ if (!plen) { @@ -1431,14 +1411,12 @@ nat64_expire_worker_walk_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, return 0; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat64_expire_worker_walk_node, static) = { .function = nat64_expire_worker_walk_fn, .type = VLIB_NODE_TYPE_INPUT, .state = VLIB_NODE_STATE_INTERRUPT, .name = "nat64-expire-worker-walk", }; -/* *INDENT-ON* */ /** * @brief Centralized process to drive per worker expire walk. @@ -1566,12 +1544,10 @@ nat64_plugin_disable () } nm->enabled = 0; - /* *INDENT-OFF* */ pool_foreach (i, nm->interfaces) { vec_add1 (interfaces, *i); } - /* *INDENT-ON* */ vec_foreach (i, interfaces) { rv = nat64_interface_add_del (i->sw_if_index, i->flags, 0); diff --git a/src/plugins/nat/nat64/nat64.h b/src/plugins/nat/nat64/nat64.h index 1180f9df778..9eb8d915390 100644 --- a/src/plugins/nat/nat64/nat64.h +++ b/src/plugins/nat/nat64/nat64.h @@ -93,14 +93,12 @@ typedef struct { ip4_address_t addr; u32 fib_index; -/* *INDENT-OFF* */ #define _(N, i, n, s) \ u16 busy_##n##_ports; \ u16 * busy_##n##_ports_per_thread; \ u32 busy_##n##_port_refcounts[65535]; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ } nat64_address_t; typedef struct diff --git a/src/plugins/nat/nat64/nat64_api.c b/src/plugins/nat/nat64/nat64_api.c index e64b6434fd2..87cca01b59b 100644 --- a/src/plugins/nat/nat64/nat64_api.c +++ b/src/plugins/nat/nat64/nat64_api.c @@ -69,7 +69,6 @@ vl_api_nat64_get_timeouts_t_handler (vl_api_nat64_get_timeouts_t * mp) vl_api_nat64_get_timeouts_reply_t *rmp; int rv = 0; - /* *INDENT-OFF* */ REPLY_MACRO2 (VL_API_NAT64_GET_TIMEOUTS_REPLY, ({ rmp->udp = htonl (nm->udp_timeout); @@ -77,7 +76,6 @@ vl_api_nat64_get_timeouts_t_handler (vl_api_nat64_get_timeouts_t * mp) rmp->tcp_transitory = htonl (nm->tcp_trans_timeout); rmp->icmp = htonl (nm->icmp_timeout); })) - /* *INDENT-ON* */ } static void @@ -298,10 +296,8 @@ vl_api_nat64_bib_dump_t_handler (vl_api_nat64_bib_dump_t * mp) .context = mp->context, }; - /* *INDENT-OFF* */ vec_foreach (db, nm->db) nat64_db_bib_walk (db, mp->proto, nat64_api_bib_walk, &ctx); - /* *INDENT-ON* */ } static int @@ -356,13 +352,11 @@ vl_api_nat64_st_dump_t_handler (vl_api_nat64_st_dump_t * mp) .context = mp->context, }; - /* *INDENT-OFF* */ vec_foreach (db, nm->db) { ctx.db = db; nat64_db_st_walk (db, mp->proto, nat64_api_st_walk, &ctx); } - /* *INDENT-ON* */ } static void diff --git a/src/plugins/nat/nat64/nat64_cli.c b/src/plugins/nat/nat64/nat64_cli.c index 3af715c2457..2cef71080f9 100644 --- a/src/plugins/nat/nat64/nat64_cli.c +++ b/src/plugins/nat/nat64/nat64_cli.c @@ -484,10 +484,8 @@ nat64_show_bib_command_fn (vlib_main_t * vm, else vlib_cli_output (vm, "NAT64 %U BIB entries:", format_nat_protocol, proto); - /* *INDENT-OFF* */ vec_foreach (db, nm->db) nat64_db_bib_walk (db, p, nat64_cli_bib_walk, vm); - /* *INDENT-ON* */ done: unformat_free (line_input); @@ -586,13 +584,11 @@ nat64_show_st_command_fn (vlib_main_t * vm, vlib_cli_output (vm, "NAT64 sessions:"); else vlib_cli_output (vm, "NAT64 %U sessions:", format_nat_protocol, proto); - /* *INDENT-OFF* */ vec_foreach (db, nm->db) { ctx.db = db; nat64_db_st_walk (db, p, nat64_cli_st_walk, &ctx); } - /* *INDENT-ON* */ done: unformat_free (line_input); @@ -775,7 +771,6 @@ done: return error; } -/* *INDENT-OFF* */ /*? * @cliexpar * @cliexstart{nat64 plugin} @@ -983,7 +978,6 @@ VLIB_CLI_COMMAND (nat64_add_interface_address_command, static) = { .short_help = "nat64 add interface address <interface> [del]", .function = nat64_add_interface_address_command_fn, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/nat64/nat64_db.c b/src/plugins/nat/nat64/nat64_db.c index 82ef70de5cf..e4e9febcb12 100644 --- a/src/plugins/nat/nat64/nat64_db.c +++ b/src/plugins/nat/nat64/nat64_db.c @@ -54,13 +54,11 @@ nat64_db_free (nat64_db_t * db) clib_bihash_free_48_8 (&db->st.in2out); clib_bihash_free_48_8 (&db->st.out2in); -/* *INDENT-OFF* */ #define _(N, i, n, s) \ pool_free (db->bib._##n##_bib); \ pool_free (db->st._##n##_st); foreach_nat_protocol #undef _ -/* *INDENT-ON* */ pool_free (db->bib._unk_proto_bib); pool_free (db->st._unk_proto_st); @@ -82,14 +80,13 @@ nat64_db_bib_entry_create (u32 thread_index, nat64_db_t * db, if (db->bib.bib_entries_num >= db->bib.limit) { db->free_addr_port_cb (db, out_addr, out_port, proto); - //nat_ipfix_logging_max_bibs (thread_index, db->bib.limit); + nat_ipfix_logging_max_bibs (thread_index, db->bib.limit); return 0; } /* create pool entry */ switch (ip_proto_to_nat_proto (proto)) { -/* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ pool_get (db->bib._##n##_bib, bibe); \ @@ -97,7 +94,6 @@ nat64_db_bib_entry_create (u32 thread_index, nat64_db_t * db, break; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ default: pool_get (db->bib._unk_proto_bib, bibe); kv.value = bibe - db->bib._unk_proto_bib; @@ -155,7 +151,6 @@ nat64_db_bib_entry_free (u32 thread_index, nat64_db_t * db, switch (ip_proto_to_nat_proto (bibe->proto)) { -/* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ bib = db->bib._##n##_bib; \ @@ -163,7 +158,6 @@ nat64_db_bib_entry_free (u32 thread_index, nat64_db_t * db, break; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ default: bib = db->bib._unk_proto_bib; st = db->st._unk_proto_st; @@ -232,14 +226,12 @@ nat64_db_bib_entry_find (nat64_db_t * db, ip46_address_t * addr, u16 port, switch (ip_proto_to_nat_proto (proto)) { -/* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ bib = db->bib._##n##_bib; \ break; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ default: bib = db->bib._unk_proto_bib; break; @@ -271,7 +263,6 @@ nat64_db_bib_walk (nat64_db_t * db, u8 proto, if (proto == 255) { - /* *INDENT-OFF* */ #define _(N, i, n, s) \ bib = db->bib._##n##_bib; \ pool_foreach (bibe, bib) { \ @@ -285,32 +276,27 @@ nat64_db_bib_walk (nat64_db_t * db, u8 proto, if (fn (bibe, ctx)) return; } - /* *INDENT-ON* */ } else { switch (ip_proto_to_nat_proto (proto)) { - /* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ bib = db->bib._##n##_bib; \ break; foreach_nat_protocol #undef _ - /* *INDENT-ON* */ default: bib = db->bib._unk_proto_bib; break; } - /* *INDENT-OFF* */ pool_foreach (bibe, bib) { if (fn (bibe, ctx)) return; } - /* *INDENT-ON* */ } } @@ -321,14 +307,12 @@ nat64_db_bib_entry_by_index (nat64_db_t * db, u8 proto, u32 bibe_index) switch (ip_proto_to_nat_proto (proto)) { -/* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ bib = db->bib._##n##_bib; \ break; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ default: bib = db->bib._unk_proto_bib; break; @@ -345,7 +329,6 @@ nat64_db_st_walk (nat64_db_t * db, u8 proto, if (proto == 255) { - /* *INDENT-OFF* */ #define _(N, i, n, s) \ st = db->st._##n##_st; \ pool_foreach (ste, st) { \ @@ -359,32 +342,27 @@ nat64_db_st_walk (nat64_db_t * db, u8 proto, if (fn (ste, ctx)) return; } - /* *INDENT-ON* */ } else { switch (ip_proto_to_nat_proto (proto)) { - /* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ st = db->st._##n##_st; \ break; foreach_nat_protocol #undef _ - /* *INDENT-ON* */ default: st = db->st._unk_proto_st; break; } - /* *INDENT-OFF* */ pool_foreach (ste, st) { if (fn (ste, ctx)) return; } - /* *INDENT-ON* */ } } @@ -401,14 +379,13 @@ nat64_db_st_entry_create (u32 thread_index, nat64_db_t * db, if (db->st.st_entries_num >= db->st.limit) { - //nat_ipfix_logging_max_sessions (thread_index, db->st.limit); + nat_ipfix_logging_max_sessions (thread_index, db->st.limit); return 0; } /* create pool entry */ switch (ip_proto_to_nat_proto (bibe->proto)) { -/* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ pool_get (db->st._##n##_st, ste); \ @@ -417,7 +394,6 @@ nat64_db_st_entry_create (u32 thread_index, nat64_db_t * db, break; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ default: pool_get (db->st._unk_proto_st, ste); kv.value = ste - db->st._unk_proto_st; @@ -494,7 +470,6 @@ nat64_db_st_entry_free (u32 thread_index, switch (ip_proto_to_nat_proto (ste->proto)) { -/* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ st = db->st._##n##_st; \ @@ -502,7 +477,6 @@ nat64_db_st_entry_free (u32 thread_index, break; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ default: st = db->st._unk_proto_st; bib = db->bib._unk_proto_bib; @@ -579,14 +553,12 @@ nat64_db_st_entry_find (nat64_db_t * db, ip46_address_t * l_addr, switch (ip_proto_to_nat_proto (proto)) { -/* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ st = db->st._##n##_st; \ break; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ default: st = db->st._unk_proto_st; break; @@ -622,14 +594,12 @@ nat64_db_st_entry_get_index (nat64_db_t * db, nat64_db_st_entry_t * ste) switch (ip_proto_to_nat_proto (ste->proto)) { -/* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ st = db->st._##n##_st; \ break; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ default: st = db->st._unk_proto_st; return (u32) ~ 0; @@ -645,14 +615,12 @@ nat64_db_st_entry_by_index (nat64_db_t * db, u8 proto, u32 ste_index) switch (ip_proto_to_nat_proto (proto)) { -/* *INDENT-OFF* */ #define _(N, i, n, s) \ case NAT_PROTOCOL_##N: \ st = db->st._##n##_st; \ break; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ default: st = db->st._unk_proto_st; break; @@ -667,7 +635,6 @@ nad64_db_st_free_expired (u32 thread_index, nat64_db_t * db, u32 now) u32 *ste_to_be_free = 0, *ste_index; nat64_db_st_entry_t *st, *ste; -/* *INDENT-OFF* */ #define _(N, i, n, s) \ st = db->st._##n##_st; \ pool_foreach (ste, st) {\ @@ -692,7 +659,6 @@ nad64_db_st_free_expired (u32 thread_index, nat64_db_t * db, u32 now) nat64_db_st_entry_free (thread_index, db, pool_elt_at_index(st, ste_index[0])); vec_free (ste_to_be_free); -/* *INDENT-ON* */ } void @@ -704,7 +670,6 @@ nat64_db_free_out_addr (u32 thread_index, nat64_db_bib_entry_t *bibe; db->addr_free = 1; -/* *INDENT-OFF* */ #define _(N, i, n, s) \ st = db->st._##n##_st; \ pool_foreach (ste, st) { \ @@ -730,7 +695,6 @@ nat64_db_free_out_addr (u32 thread_index, pool_elt_at_index(st, ste_index[0])); vec_free (ste_to_be_free); db->addr_free = 0; -/* *INDENT-ON* */ } /* diff --git a/src/plugins/nat/nat64/nat64_db.h b/src/plugins/nat/nat64/nat64_db.h index c34b671999a..a7d433fb8ea 100644 --- a/src/plugins/nat/nat64/nat64_db.h +++ b/src/plugins/nat/nat64/nat64_db.h @@ -47,7 +47,6 @@ typedef struct }; } nat64_db_bib_entry_key_t; -/* *INDENT-OFF* */ typedef CLIB_PACKED(struct { ip6_address_t in_addr; @@ -59,17 +58,14 @@ typedef CLIB_PACKED(struct u8 proto; u8 is_static; }) nat64_db_bib_entry_t; -/* *INDENT-ON* */ typedef struct { /* BIBs */ -/* *INDENT-OFF* */ #define _(N, i, n, s) \ nat64_db_bib_entry_t *_##n##_bib; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ nat64_db_bib_entry_t *_unk_proto_bib; /* BIB lookup */ @@ -98,7 +94,6 @@ typedef struct }; } nat64_db_st_entry_key_t; -/* *INDENT-OFF* */ typedef CLIB_PACKED(struct { ip6_address_t in_r_addr; @@ -109,17 +104,14 @@ typedef CLIB_PACKED(struct u8 proto; u8 tcp_state; }) nat64_db_st_entry_t; -/* *INDENT-ON* */ typedef struct { /* session tables */ -/* *INDENT-OFF* */ #define _(N, i, n, s) \ nat64_db_st_entry_t *_##n##_st; foreach_nat_protocol #undef _ -/* *INDENT-ON* */ nat64_db_st_entry_t *_unk_proto_st; /* session lookup */ diff --git a/src/plugins/nat/nat64/nat64_in2out.c b/src/plugins/nat/nat64/nat64_in2out.c index 52d3c7f0a3b..63eab72a7fb 100644 --- a/src/plugins/nat/nat64/nat64_in2out.c +++ b/src/plugins/nat/nat64/nat64_in2out.c @@ -86,14 +86,12 @@ nat64_not_translate (u32 sw_if_index, ip6_address_t ip6_addr) ip_lookup_main_t *lm6 = &im6->lookup_main; ip_interface_address_t *ia = 0; - /* *INDENT-OFF* */ foreach_ip_interface_address (lm6, ia, sw_if_index, 0, ({ addr = ip_interface_address_get_address (lm6, ia); if (0 == ip6_address_compare (addr, &ip6_addr)) return 1; })); - /* *INDENT-ON* */ return 0; } @@ -744,7 +742,6 @@ nat64_in2out_tcp_udp_hairpinning (vlib_main_t * vm, vlib_buffer_t * b, daddr.ip4.as_u32 = ste->out_r_addr.as_u32; bibe = 0; - /* *INDENT-OFF* */ vec_foreach (db, nm->db) { bibe = nat64_db_bib_entry_find (db, &daddr, dport, proto, 0, 0); @@ -752,7 +749,6 @@ nat64_in2out_tcp_udp_hairpinning (vlib_main_t * vm, vlib_buffer_t * b, if (bibe) break; } - /* *INDENT-ON* */ if (!bibe) return -1; @@ -851,7 +847,6 @@ nat64_in2out_icmp_hairpinning (vlib_main_t * vm, vlib_buffer_t * b, daddr.ip4.as_u32 = bibe->out_addr.as_u32; ste = 0; - /* *INDENT-OFF* */ vec_foreach (db, nm->db) { ste = nat64_db_st_entry_find (db, &saddr, &daddr, sport, dport, proto, @@ -860,7 +855,6 @@ nat64_in2out_icmp_hairpinning (vlib_main_t * vm, vlib_buffer_t * b, if (ste) break; } - /* *INDENT-ON* */ if (!ste) return -1; @@ -1006,7 +1000,6 @@ nat64_in2out_unk_proto_hairpinning (vlib_main_t * vm, vlib_buffer_t * b, daddr.ip4.as_u32 = ste->out_r_addr.as_u32; bibe = 0; - /* *INDENT-OFF* */ vec_foreach (db, nm->db) { bibe = nat64_db_bib_entry_find (db, &daddr, 0, proto, 0, 0); @@ -1014,7 +1007,6 @@ nat64_in2out_unk_proto_hairpinning (vlib_main_t * vm, vlib_buffer_t * b, if (bibe) break; } - /* *INDENT-ON* */ if (!bibe) return -1; @@ -1226,7 +1218,6 @@ VLIB_NODE_FN (nat64_in2out_node) (vlib_main_t * vm, return nat64_in2out_node_fn_inline (vm, node, frame, 0); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat64_in2out_node) = { .name = "nat64-in2out", .vector_size = sizeof (u32), @@ -1243,7 +1234,6 @@ VLIB_REGISTER_NODE (nat64_in2out_node) = { [NAT64_IN2OUT_NEXT_SLOWPATH] = "nat64-in2out-slowpath", }, }; -/* *INDENT-ON* */ VLIB_NODE_FN (nat64_in2out_slowpath_node) (vlib_main_t * vm, vlib_node_runtime_t * node, @@ -1252,7 +1242,6 @@ VLIB_NODE_FN (nat64_in2out_slowpath_node) (vlib_main_t * vm, return nat64_in2out_node_fn_inline (vm, node, frame, 1); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat64_in2out_slowpath_node) = { .name = "nat64-in2out-slowpath", .vector_size = sizeof (u32), @@ -1269,7 +1258,6 @@ VLIB_REGISTER_NODE (nat64_in2out_slowpath_node) = { [NAT64_IN2OUT_NEXT_SLOWPATH] = "nat64-in2out-slowpath", }, }; -/* *INDENT-ON* */ typedef struct nat64_in2out_frag_set_ctx_t_ { @@ -1384,7 +1372,6 @@ VLIB_NODE_FN (nat64_in2out_handoff_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat64_in2out_handoff_node) = { .name = "nat64-in2out-handoff", .vector_size = sizeof (u32), @@ -1399,7 +1386,6 @@ VLIB_REGISTER_NODE (nat64_in2out_handoff_node) = { [0] = "error-drop", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/nat64/nat64_out2in.c b/src/plugins/nat/nat64/nat64_out2in.c index 7cc2d3d3b70..a8faead4470 100644 --- a/src/plugins/nat/nat64/nat64_out2in.c +++ b/src/plugins/nat/nat64/nat64_out2in.c @@ -639,7 +639,6 @@ VLIB_NODE_FN (nat64_out2in_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat64_out2in_node) = { .name = "nat64-out2in", .vector_size = sizeof (u32), @@ -655,7 +654,6 @@ VLIB_REGISTER_NODE (nat64_out2in_node) = { [NAT64_OUT2IN_NEXT_IP4_LOOKUP] = "ip4-lookup", }, }; -/* *INDENT-ON* */ typedef struct nat64_out2in_frag_set_ctx_t_ { @@ -769,7 +767,6 @@ VLIB_NODE_FN (nat64_out2in_handoff_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat64_out2in_handoff_node) = { .name = "nat64-out2in-handoff", .vector_size = sizeof (u32), @@ -784,7 +781,6 @@ VLIB_REGISTER_NODE (nat64_out2in_handoff_node) = { [0] = "error-drop", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/nat66/nat66_cli.c b/src/plugins/nat/nat66/nat66_cli.c index 0ca40875584..9ef8d056685 100644 --- a/src/plugins/nat/nat66/nat66_cli.c +++ b/src/plugins/nat/nat66/nat66_cli.c @@ -330,16 +330,16 @@ nat66_show_static_mappings_command_fn (vlib_main_t * vm, * @cliexpar * @cliexstart{nat66} * To enable NAT66 plugin - * vpp# nat66 enable + * vpp# nat66 plugin enable * To disable NAT66 plugin - * vpp# nat66 disable + * vpp# nat66 plugin disable * To enable NAT66 plugin with outside-vrf id 10 - * vpp# nat66 enable outside-vrf 10 + * vpp# nat66 plugin enable outside-vrf 10 * @cliexend ?*/ VLIB_CLI_COMMAND (nat66_enable_disable_command, static) = { - .path = "nat66", - .short_help = "nat66 <enable [outside-vrf <vrf-id>]>|disable", + .path = "nat66 plugin", + .short_help = "nat66 plugin <enable [outside-vrf <vrf-id>]>|disable", .function = nat66_enable_disable_command_fn, }; diff --git a/src/plugins/nat/nat66/nat66_in2out.c b/src/plugins/nat/nat66/nat66_in2out.c index 356100f89ef..aa2229e1997 100644 --- a/src/plugins/nat/nat66/nat66_in2out.c +++ b/src/plugins/nat/nat66/nat66_in2out.c @@ -94,14 +94,12 @@ nat66_not_translate (u32 rx_fib_index, ip6_address_t ip6_addr) sw_if_index = fib_entry_get_resolving_interface (fei); } - /* *INDENT-OFF* */ pool_foreach (i, nm->interfaces) { /* NAT packet aimed at outside interface */ if (nat66_interface_is_outside (i) && sw_if_index == i->sw_if_index) return 0; } - /* *INDENT-ON* */ return 1; } @@ -235,7 +233,6 @@ VLIB_NODE_FN (nat66_in2out_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat66_in2out_node) = { .name = "nat66-in2out", .vector_size = sizeof (u32), @@ -250,7 +247,6 @@ VLIB_REGISTER_NODE (nat66_in2out_node) = { [NAT66_IN2OUT_NEXT_IP6_LOOKUP] = "ip6-lookup", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/nat66/nat66_out2in.c b/src/plugins/nat/nat66/nat66_out2in.c index 9d44b4880eb..820e0c79033 100644 --- a/src/plugins/nat/nat66/nat66_out2in.c +++ b/src/plugins/nat/nat66/nat66_out2in.c @@ -193,7 +193,6 @@ VLIB_NODE_FN (nat66_out2in_node) (vlib_main_t * vm, return frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (nat66_out2in_node) = { .name = "nat66-out2in", .vector_size = sizeof (u32), @@ -208,7 +207,6 @@ VLIB_REGISTER_NODE (nat66_out2in_node) = { [NAT66_OUT2IN_NEXT_IP6_LOOKUP] = "ip6-lookup", }, }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/nat/pnat/pnat.api b/src/plugins/nat/pnat/pnat.api index b6632159d7c..de555c41412 100644 --- a/src/plugins/nat/pnat/pnat.api +++ b/src/plugins/nat/pnat/pnat.api @@ -26,6 +26,7 @@ enum pnat_mask PNAT_DPORT = 0x8, PNAT_COPY_BYTE = 0x10, PNAT_CLEAR_BYTE = 0x20, + PNAT_PROTO = 0x40, }; enum pnat_attachment_point @@ -65,6 +66,7 @@ autoendian define pnat_binding_add vl_api_pnat_rewrite_tuple_t rewrite; }; + autoendian define pnat_binding_add_reply { u32 context; @@ -72,6 +74,22 @@ autoendian define pnat_binding_add_reply u32 binding_index; }; +autoendian define pnat_binding_add_v2 +{ + u32 client_index; + u32 context; + vl_api_pnat_match_tuple_t match; + vl_api_pnat_rewrite_tuple_t rewrite; +}; + + +autoendian define pnat_binding_add_v2_reply +{ + u32 context; + i32 retval; + u32 binding_index; +}; + autoendian autoreply define pnat_binding_del { u32 client_index; diff --git a/src/plugins/nat/pnat/pnat.c b/src/plugins/nat/pnat/pnat.c index 547b063f286..2b4a6b49e96 100644 --- a/src/plugins/nat/pnat/pnat.c +++ b/src/plugins/nat/pnat/pnat.c @@ -56,7 +56,9 @@ static pnat_mask_fast_t pnat_mask2fast(pnat_mask_t lookup_mask) { m.as_u64[0] = 0xffffffff00000000; if (lookup_mask & PNAT_DA) m.as_u64[0] |= 0x00000000ffffffff; - m.as_u64[1] = 0xffffffff00000000; + m.as_u64[1] = 0x00ffffff00000000; + if (lookup_mask & PNAT_PROTO) + m.as_u64[1] |= 0xff00000000000000; if (lookup_mask & PNAT_SPORT) m.as_u64[1] |= 0x00000000ffff0000; if (lookup_mask & PNAT_DPORT) diff --git a/src/plugins/nat/pnat/pnat_api.c b/src/plugins/nat/pnat/pnat_api.c index 2c4a1382d2a..a4e7ff192bf 100644 --- a/src/plugins/nat/pnat/pnat_api.c +++ b/src/plugins/nat/pnat/pnat_api.c @@ -13,6 +13,7 @@ * limitations under the License. */ #include "pnat.h" +#include <vnet/vnet.h> #include <pnat/pnat.api_enum.h> #include <pnat/pnat.api_types.h> #include <vlibmemory/api.h> @@ -35,22 +36,33 @@ static void vl_api_pnat_binding_add_t_handler(vl_api_pnat_binding_add_t *mp) { pnat_main_t *pm = &pnat_main; vl_api_pnat_binding_add_reply_t *rmp; u32 binding_index; + + // for backward compatibility + if (mp->match.proto == 0) + mp->match.mask |= PNAT_PROTO; + int rv = pnat_binding_add(&mp->match, &mp->rewrite, &binding_index); REPLY_MACRO2_END(VL_API_PNAT_BINDING_ADD_REPLY, ({ rmp->binding_index = binding_index; })); } static void +vl_api_pnat_binding_add_v2_t_handler(vl_api_pnat_binding_add_t *mp) { + pnat_main_t *pm = &pnat_main; + vl_api_pnat_binding_add_reply_t *rmp; + u32 binding_index; + int rv = pnat_binding_add(&mp->match, &mp->rewrite, &binding_index); + REPLY_MACRO2_END(VL_API_PNAT_BINDING_ADD_V2_REPLY, + ({ rmp->binding_index = binding_index; })); +} + +static void vl_api_pnat_binding_attach_t_handler(vl_api_pnat_binding_attach_t *mp) { pnat_main_t *pm = &pnat_main; vl_api_pnat_binding_attach_reply_t *rmp; int rv; - /* Ensure that the interface exists */ - if (!vnet_sw_if_index_is_api_valid(mp->sw_if_index)) { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto bad_sw_if_index; - } + VALIDATE_SW_IF_INDEX_END(mp); rv = pnat_binding_attach(mp->sw_if_index, mp->attachment, mp->binding_index); @@ -65,11 +77,7 @@ vl_api_pnat_binding_detach_t_handler(vl_api_pnat_binding_detach_t *mp) { vl_api_pnat_binding_detach_reply_t *rmp; int rv; - /* Ensure that the interface exists */ - if (!vnet_sw_if_index_is_api_valid(mp->sw_if_index)) { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto bad_sw_if_index; - } + VALIDATE_SW_IF_INDEX_END(mp); rv = pnat_binding_detach(mp->sw_if_index, mp->attachment, mp->binding_index); @@ -108,7 +116,8 @@ static void send_bindings_details(u32 index, vl_api_registration_t *rp, /* Endian hack until apigen registers _details * endian functions */ - vl_api_pnat_bindings_details_t_endian(rmp); + vl_api_pnat_bindings_details_t_endian( + rmp, 1 /* to network */); rmp->_vl_msg_id = htons(rmp->_vl_msg_id); rmp->context = htonl(rmp->context); })); @@ -150,7 +159,7 @@ static void send_interfaces_details(u32 index, vl_api_registration_t *rp, /* Endian hack until apigen registers _details * endian functions */ - vl_api_pnat_interfaces_details_t_endian(rmp); + vl_api_pnat_interfaces_details_t_endian(rmp, 1 /* to network */); rmp->_vl_msg_id = htons(rmp->_vl_msg_id); rmp->context = htonl(rmp->context); })); diff --git a/src/plugins/nat/pnat/pnat_cli.c b/src/plugins/nat/pnat/pnat_cli.c index 082f0778acb..ce9beee540d 100644 --- a/src/plugins/nat/pnat/pnat_cli.c +++ b/src/plugins/nat/pnat/pnat_cli.c @@ -122,6 +122,8 @@ uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args) { t->mask |= PNAT_SA; else if (unformat(input, "dst %U", unformat_ip4_address, &t->dst)) t->mask |= PNAT_DA; + else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto)) + t->mask |= PNAT_PROTO; else if (unformat(input, "sport %d", &sport)) { if (sport == 0 || sport > 65535) return 0; @@ -132,9 +134,7 @@ uword unformat_pnat_match_tuple(unformat_input_t *input, va_list *args) { return 0; t->mask |= PNAT_DPORT; t->dport = dport; - } else if (unformat(input, "proto %U", unformat_ip_protocol, &t->proto)) - ; - else + } else break; } return 1; diff --git a/src/plugins/nat/pnat/pnat_node.h b/src/plugins/nat/pnat/pnat_node.h index 595189c2efb..f1afb450934 100644 --- a/src/plugins/nat/pnat/pnat_node.h +++ b/src/plugins/nat/pnat/pnat_node.h @@ -20,6 +20,7 @@ #include <pnat/pnat.api_enum.h> #include <vnet/feature/feature.h> #include <vnet/udp/udp_packet.h> +#include <vnet/tcp/tcp_packet.h> #include <vnet/ip/format.h> /* PNAT next-nodes */ diff --git a/src/plugins/nat/pnat/tests/pnat_test.c b/src/plugins/nat/pnat/tests/pnat_test.c index e7d946941b9..f515dd6d376 100644 --- a/src/plugins/nat/pnat/tests/pnat_test.c +++ b/src/plugins/nat/pnat/tests/pnat_test.c @@ -25,6 +25,11 @@ #include <vnet/fib/ip4_fib.h> #include "../pnat.h" #include <pnat/pnat.api_enum.h> /* For error counters */ +#ifdef __FreeBSD__ +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/in.h> +#endif /* __FreeBSD__ */ #include <arpa/inet.h> #include "pnat_test_stubs.h" @@ -569,7 +574,8 @@ int main(int argc, char **argv) { ip_checksum_init(vm); - u32 node_index = vlib_register_node(vm, &pnat_input_node); + u32 node_index = + vlib_register_node(vm, &pnat_input_node, "%s", pnat_input_node.name); node = vlib_node_get_runtime(vm, node_index); assert(node); diff --git a/src/plugins/nat/pnat/tests/pnat_test_stubs.h b/src/plugins/nat/pnat/tests/pnat_test_stubs.h index bfe1838ffa4..2dc59ac8586 100644 --- a/src/plugins/nat/pnat/tests/pnat_test_stubs.h +++ b/src/plugins/nat/pnat/tests/pnat_test_stubs.h @@ -19,12 +19,6 @@ void os_panic(void) {} void os_exit(int code) {} u32 ip4_fib_table_get_index_for_sw_if_index(u32 sw_if_index) { return 0; } -#include <vpp/stats/stat_segment.h> -clib_error_t *stat_segment_register_gauge(u8 *names, - stat_segment_update_fn update_fn, - u32 index) { - return 0; -}; #include <vnet/feature/feature.h> vnet_feature_main_t feature_main; void classify_get_trace_chain(void){}; diff --git a/src/plugins/nat/pnat/tests/test_genpackets.py b/src/plugins/nat/pnat/tests/test_genpackets.py index 9d32d3e3656..40867317078 100755 --- a/src/plugins/nat/pnat/tests/test_genpackets.py +++ b/src/plugins/nat/pnat/tests/test_genpackets.py @@ -6,33 +6,35 @@ from importlib.machinery import SourceFileLoader from scapy.all import * from scapy.contrib.geneve import GENEVE + def hexstring(p): s = bytes(p.__class__(p)) return ",".join("0x{:02x}".format(c) for c in s) + def output_test(filename, tests): (name, ext) = os.path.basename(filename).split(".") - print('/* DO NOT EDIT: automatically generated by test_genpackets.py */') - print('/* clang-format off */') - print('test_t tests_{}[] = {{'.format(name)) + print("/* DO NOT EDIT: automatically generated by test_genpackets.py */") + print("/* clang-format off */") + print("test_t tests_{}[] = {{".format(name)) for t in tests: - print(' {') + print(" {") print(' .name = "{}",'.format(t[0])) - print(' .nsend = {},'.format(len(t[1]))) - print(' .send = (char []){{{}}},'.format(hexstring(t[1]))) - print(' .nexpect = {},'.format(len(t[2]))) - print(' .expect = (char []){{{}}},'.format(hexstring(t[2]))) - print(' .expect_next_index = {}'.format(t[3])) - print(' },') - print('};') - print('/* clang-format on */') + print(" .nsend = {},".format(len(t[1]))) + print(" .send = (char []){{{}}},".format(hexstring(t[1]))) + print(" .nexpect = {},".format(len(t[2]))) + print(" .expect = (char []){{{}}},".format(hexstring(t[2]))) + print(" .expect_next_index = {}".format(t[3])) + print(" },") + print("};") + print("/* clang-format on */") + # Read tests from file for filename in sys.argv[1:]: with open(filename) as f: - content = f.read().replace('\n', '') + content = f.read().replace("\n", "") tests = eval(content) output_test(filename, tests) - |