aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/nat/nat44-ei
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/nat/nat44-ei')
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei.api85
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei.c2589
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei.h142
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_api.c399
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_cli.c249
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_ha.c8
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_ha_doc.md70
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_ha_doc.rst88
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_hairpinning.c756
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_hairpinning.h92
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_handoff.c3
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_in2out.c1215
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_inlines.h24
-rw-r--r--src/plugins/nat/nat44-ei/nat44_ei_out2in.c218
14 files changed, 2997 insertions, 2941 deletions
diff --git a/src/plugins/nat/nat44-ei/nat44_ei.api b/src/plugins/nat/nat44-ei/nat44_ei.api
index 9ea1a3a1dde..6d24b541e8d 100644
--- a/src/plugins/nat/nat44-ei/nat44_ei.api
+++ b/src/plugins/nat/nat44-ei/nat44_ei.api
@@ -550,6 +550,45 @@ define nat44_ei_interface_output_feature_details {
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
+ @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
+*/
+autoendian autoreply define nat44_ei_add_del_output_interface {
+ u32 client_index;
+ u32 context;
+ bool is_add;
+ vl_api_interface_index_t sw_if_index;
+};
+
+service {
+ rpc nat44_ei_output_interface_get returns nat44_ei_output_interface_get_reply
+ stream nat44_ei_output_interface_details;
+};
+
+define nat44_ei_output_interface_get
+{
+ u32 client_index;
+ u32 context;
+ u32 cursor;
+};
+
+define nat44_ei_output_interface_get_reply
+{
+ u32 context;
+ i32 retval;
+ u32 cursor;
+};
+
+define nat44_ei_output_interface_details
+{
+ u32 context;
+ vl_api_interface_index_t sw_if_index;
+};
+
/** \brief Add/delete NAT44 static mapping
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@@ -784,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 3c9a9a85346..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);
@@ -304,6 +309,76 @@ nat_validate_interface_counters (nat44_ei_main_t *nm, u32 sw_if_index)
nat_validate_simple_counter (nm->counters.hairpinning, sw_if_index);
}
+static void
+nat44_ei_add_del_addr_to_fib_foreach_out_if (ip4_address_t *addr, u8 is_add)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_interface_t *i;
+
+ pool_foreach (i, nm->interfaces)
+ {
+ if (nat44_ei_interface_is_outside (i) && !nm->out2in_dpo)
+ {
+ nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add);
+ }
+ }
+ pool_foreach (i, nm->output_feature_interfaces)
+ {
+ if (nat44_ei_interface_is_outside (i) && !nm->out2in_dpo)
+ {
+ nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add);
+ }
+ }
+}
+
+static_always_inline void
+nat44_ei_add_del_addr_to_fib_foreach_addr (u32 sw_if_index, u8 is_add)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_address_t *ap;
+
+ vec_foreach (ap, nm->addresses)
+ {
+ nat44_ei_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, is_add);
+ }
+}
+
+static_always_inline void
+nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (u32 sw_if_index, u8 is_add)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_static_mapping_t *m;
+
+ pool_foreach (m, nm->static_mappings)
+ {
+ if (is_sm_addr_only (m->flags) &&
+ !(m->local_addr.as_u32 == m->external_addr.as_u32))
+ {
+ nat44_ei_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index,
+ is_add);
+ }
+ }
+}
+
+static int
+nat44_ei_is_address_used_in_static_mapping (ip4_address_t addr)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_static_mapping_t *m;
+ pool_foreach (m, nm->static_mappings)
+ {
+ if (is_sm_addr_only (m->flags) || is_sm_identity_nat (m->flags))
+ {
+ continue;
+ }
+ if (m->external_addr.as_u32 == addr.as_u32)
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
clib_error_t *
nat44_ei_init (vlib_main_t *vm)
{
@@ -372,14 +447,15 @@ nat44_ei_init (vlib_main_t *vm)
/* Use all available workers by default */
if (nm->num_workers > 1)
{
-
for (i = 0; i < nm->num_workers; i++)
bitmap = clib_bitmap_set (bitmap, i, 1);
nat44_ei_set_workers (bitmap);
clib_bitmap_free (bitmap);
}
else
- nm->per_thread_data[0].snat_thread_index = 0;
+ {
+ nm->per_thread_data[0].snat_thread_index = 0;
+ }
/* callbacks to call when interface address changes. */
cbi.function = nat44_ei_ip4_add_del_interface_address_cb;
@@ -402,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);
@@ -466,43 +540,104 @@ 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);
+ if (nm->num_workers > 1)
+ {
+ if (nm->fq_in2out_index == ~0)
+ {
+ nm->fq_in2out_index = vlib_frame_queue_main_init (
+ nm->in2out_node_index, nm->frame_queue_nelts);
+ }
+ if (nm->fq_out2in_index == ~0)
+ {
+ nm->fq_out2in_index = vlib_frame_queue_main_init (
+ nm->out2in_node_index, nm->frame_queue_nelts);
+ }
+ if (nm->fq_in2out_output_index == ~0)
+ {
+ nm->fq_in2out_output_index = vlib_frame_queue_main_init (
+ nm->in2out_output_node_index, nm->frame_queue_nelts);
+ }
+ }
+
nat_ha_enable ();
nm->enabled = 1;
return 0;
}
-void
-nat44_ei_addresses_free (nat44_ei_address_t **addresses)
+static_always_inline nat44_ei_outside_fib_t *
+nat44_ei_get_outside_fib (nat44_ei_outside_fib_t *outside_fibs, u32 fib_index)
{
- nat44_ei_address_t *ap;
- vec_foreach (ap, *addresses)
+ nat44_ei_outside_fib_t *f;
+ vec_foreach (f, outside_fibs)
{
-#define _(N, i, n, s) vec_free (ap->busy_##n##_ports_per_thread);
- foreach_nat_protocol
-#undef _
+ if (f->fib_index == fib_index)
+ {
+ return f;
+ }
}
- vec_free (*addresses);
- *addresses = 0;
+ return 0;
+}
+
+static_always_inline nat44_ei_interface_t *
+nat44_ei_get_interface (nat44_ei_interface_t *interfaces, u32 sw_if_index)
+{
+ nat44_ei_interface_t *i;
+ pool_foreach (i, interfaces)
+ {
+ if (i->sw_if_index == sw_if_index)
+ {
+ return i;
+ }
+ }
+ return 0;
+}
+
+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_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
+nat44_ei_add_interface (u32 sw_if_index, u8 is_inside)
{
const char *feature_name, *del_feature_name;
nat44_ei_main_t *nm = &nat44_ei_main;
- nat44_ei_interface_t *i;
- nat44_ei_address_t *ap;
- nat44_ei_static_mapping_t *m;
+
nat44_ei_outside_fib_t *outside_fib;
- u32 fib_index =
- fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
+ nat44_ei_interface_t *i;
+ u32 fib_index;
+ int rv;
fail_if_disabled ();
@@ -512,470 +647,665 @@ nat44_ei_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
return VNET_API_ERROR_UNSUPPORTED;
}
- pool_foreach (i, nm->output_feature_interfaces)
+ if (nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index))
{
- if (i->sw_if_index == sw_if_index)
+ nat44_ei_log_err ("error interface already configured");
+ return VNET_API_ERROR_VALUE_EXIST;
+ }
+
+ i = nat44_ei_get_interface (nm->interfaces, sw_if_index);
+ if (i)
+ {
+ if ((nat44_ei_interface_is_inside (i) && is_inside) ||
+ (nat44_ei_interface_is_outside (i) && !is_inside))
{
- nat44_ei_log_err ("error interface already configured");
- return VNET_API_ERROR_VALUE_EXIST;
+ return 0;
+ }
+ if (nm->num_workers > 1)
+ {
+ del_feature_name = !is_inside ? "nat44-ei-in2out-worker-handoff" :
+ "nat44-ei-out2in-worker-handoff";
+ feature_name = "nat44-ei-handoff-classify";
+ }
+ else
+ {
+ del_feature_name =
+ !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
+
+ feature_name = "nat44-ei-classify";
}
- }
- if (nm->static_mapping_only && !(nm->static_mapping_connection_tracking))
- feature_name = is_inside ? "nat44-ei-in2out-fast" : "nat44-ei-out2in-fast";
+ rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
+ if (rv)
+ {
+ return rv;
+ }
+ rv = vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
+ sw_if_index, 0, 0, 0);
+ if (rv)
+ {
+ return rv;
+ }
+ rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
+ sw_if_index, 1, 0, 0);
+ if (rv)
+ {
+ return rv;
+ }
+ if (!is_inside)
+ {
+ rv = nat44_ei_hairpinning_enable (0);
+ if (rv)
+ {
+ return rv;
+ }
+ }
+ }
else
{
if (nm->num_workers > 1)
- feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" :
- "nat44-ei-out2in-worker-handoff";
+ {
+ feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" :
+ "nat44-ei-out2in-worker-handoff";
+ }
else
- feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
- }
+ {
+ feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
+ }
+ nat_validate_interface_counters (nm, sw_if_index);
+
+ rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
+ if (rv)
+ {
+ return rv;
+ }
+ rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
+ sw_if_index, 1, 0, 0);
+ if (rv)
+ {
+ return rv;
+ }
+ if (is_inside && !nm->out2in_dpo)
+ {
+ rv = nat44_ei_hairpinning_enable (1);
+ if (rv)
+ {
+ return rv;
+ }
+ }
- if (nm->fq_in2out_index == ~0 && nm->num_workers > 1)
- nm->fq_in2out_index = vlib_frame_queue_main_init (nm->in2out_node_index,
- nm->frame_queue_nelts);
+ pool_get (nm->interfaces, i);
+ i->sw_if_index = sw_if_index;
+ i->flags = 0;
+ }
- if (nm->fq_out2in_index == ~0 && nm->num_workers > 1)
- nm->fq_out2in_index = vlib_frame_queue_main_init (nm->out2in_node_index,
- nm->frame_queue_nelts);
+ fib_index =
+ fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
if (!is_inside)
{
- vec_foreach (outside_fib, nm->outside_fibs)
+ i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
+
+ outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
+ if (outside_fib)
{
- if (outside_fib->fib_index == fib_index)
- {
- if (is_del)
- {
- outside_fib->refcount--;
- if (!outside_fib->refcount)
- vec_del1 (nm->outside_fibs,
- outside_fib - nm->outside_fibs);
- }
- else
- outside_fib->refcount++;
- goto feature_set;
- }
+ outside_fib->refcount++;
}
- if (!is_del)
+ else
{
vec_add2 (nm->outside_fibs, outside_fib, 1);
- outside_fib->refcount = 1;
outside_fib->fib_index = fib_index;
+ outside_fib->refcount = 1;
}
- }
-feature_set:
- pool_foreach (i, nm->interfaces)
+ 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);
+ }
+ else
{
- if (i->sw_if_index == sw_if_index)
- {
- if (is_del)
- {
- if (nat44_ei_interface_is_inside (i) &&
- nat44_ei_interface_is_outside (i))
- {
- if (is_inside)
- i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
- else
- i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
+ i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
+ }
- if (nm->num_workers > 1)
- {
- del_feature_name = "nat44-ei-handoff-classify";
- clib_warning (
- "del_feature_name = nat44-ei-handoff-classify");
- feature_name = !is_inside ?
- "nat44-ei-in2out-worker-handoff" :
- "nat44-ei-out2in-worker-handoff";
- }
- else
- {
- del_feature_name = "nat44-ei-classify";
- clib_warning ("del_feature_name = nat44-ei-classify");
- feature_name =
- !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
- }
+ return 0;
+}
- int rv =
- ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
- if (rv)
- return rv;
- rv = vnet_feature_enable_disable (
- "ip4-unicast", del_feature_name, sw_if_index, 0, 0, 0);
- if (rv)
- return rv;
- rv = vnet_feature_enable_disable (
- "ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
- if (rv)
- return rv;
- if (!is_inside)
- {
- rv = vnet_feature_enable_disable ("ip4-local",
- "nat44-ei-hairpinning",
- sw_if_index, 1, 0, 0);
- if (rv)
- return rv;
- }
- }
- else
- {
- int rv =
- ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
- if (rv)
- return rv;
- rv = vnet_feature_enable_disable (
- "ip4-unicast", feature_name, sw_if_index, 0, 0, 0);
- if (rv)
- return rv;
- pool_put (nm->interfaces, i);
- if (is_inside)
- {
- rv = vnet_feature_enable_disable ("ip4-local",
- "nat44-ei-hairpinning",
- sw_if_index, 0, 0, 0);
- if (rv)
- return rv;
- }
- }
- }
- else
- {
- if ((nat44_ei_interface_is_inside (i) && is_inside) ||
- (nat44_ei_interface_is_outside (i) && !is_inside))
- return 0;
+int
+nat44_ei_del_interface (u32 sw_if_index, u8 is_inside)
+{
+ const char *feature_name, *del_feature_name;
+ nat44_ei_main_t *nm = &nat44_ei_main;
- if (nm->num_workers > 1)
- {
- del_feature_name = !is_inside ?
- "nat44-ei-in2out-worker-handoff" :
- "nat44-ei-out2in-worker-handoff";
- feature_name = "nat44-ei-handoff-classify";
- clib_warning ("feature_name = nat44-ei-handoff-classify");
- }
- else
- {
- del_feature_name =
- !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
- feature_name = "nat44-ei-classify";
- clib_warning ("feature_name = nat44-ei-classify");
- }
+ nat44_ei_outside_fib_t *outside_fib;
+ nat44_ei_interface_t *i;
+ u32 fib_index;
+ int rv;
- int rv =
- ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
- if (rv)
- return rv;
- rv = vnet_feature_enable_disable (
- "ip4-unicast", del_feature_name, sw_if_index, 0, 0, 0);
- if (rv)
- return rv;
- rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
- sw_if_index, 1, 0, 0);
- if (rv)
- return rv;
- if (!is_inside)
- {
- rv = vnet_feature_enable_disable (
- "ip4-local", "nat44-ei-hairpinning", sw_if_index, 0, 0, 0);
- if (rv)
- return rv;
- }
- goto set_flags;
- }
+ fail_if_disabled ();
- goto fib;
- }
+ if (nm->out2in_dpo && !is_inside)
+ {
+ nat44_ei_log_err ("error unsupported");
+ return VNET_API_ERROR_UNSUPPORTED;
}
- if (is_del)
+ i = nat44_ei_get_interface (nm->interfaces, sw_if_index);
+ if (i == 0)
{
nat44_ei_log_err ("error interface couldn't be found");
return VNET_API_ERROR_NO_SUCH_ENTRY;
}
- pool_get (nm->interfaces, i);
- i->sw_if_index = sw_if_index;
- i->flags = 0;
- nat_validate_interface_counters (nm, sw_if_index);
-
- int rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
- sw_if_index, 1, 0, 0);
- if (rv)
- return rv;
-
- rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
- if (rv)
- return rv;
-
- if (is_inside && !nm->out2in_dpo)
+ if (nat44_ei_interface_is_inside (i) && nat44_ei_interface_is_outside (i))
{
- rv = vnet_feature_enable_disable ("ip4-local", "nat44-ei-hairpinning",
+ if (nm->num_workers > 1)
+ {
+ del_feature_name = "nat44-ei-handoff-classify";
+ feature_name = !is_inside ? "nat44-ei-in2out-worker-handoff" :
+ "nat44-ei-out2in-worker-handoff";
+ }
+ else
+ {
+ del_feature_name = "nat44-ei-classify";
+ feature_name = !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
+ }
+
+ rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
+ if (rv)
+ {
+ return rv;
+ }
+ rv = vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
+ sw_if_index, 0, 0, 0);
+ if (rv)
+ {
+ return rv;
+ }
+ rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
sw_if_index, 1, 0, 0);
if (rv)
- return rv;
- }
-
-set_flags:
- if (is_inside)
- {
- i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
- return 0;
+ {
+ return rv;
+ }
+ if (is_inside)
+ {
+ i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
+ }
+ else
+ {
+ rv = nat44_ei_hairpinning_enable (1);
+ if (rv)
+ {
+ return rv;
+ }
+ i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
+ }
}
else
- i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
+ {
+ if (nm->num_workers > 1)
+ {
+ feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" :
+ "nat44-ei-out2in-worker-handoff";
+ }
+ else
+ {
+ feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
+ }
- /* Add/delete external addresses to FIB */
-fib:
- vec_foreach (ap, nm->addresses)
- nat44_ei_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, !is_del);
+ rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
+ if (rv)
+ {
+ return rv;
+ }
+ rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
+ sw_if_index, 0, 0, 0);
+ if (rv)
+ {
+ return rv;
+ }
+ if (is_inside)
+ {
+ rv = nat44_ei_hairpinning_enable (0);
+ if (rv)
+ {
+ return rv;
+ }
+ }
- pool_foreach (m, nm->static_mappings)
+ // remove interface
+ pool_put (nm->interfaces, i);
+ }
+
+ if (!is_inside)
{
- if (!(nat44_ei_is_addr_only_static_mapping (m)) ||
- (m->local_addr.as_u32 == m->external_addr.as_u32))
- continue;
+ fib_index =
+ fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
+ outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
+ if (outside_fib)
+ {
+ outside_fib->refcount--;
+ if (!outside_fib->refcount)
+ {
+ vec_del1 (nm->outside_fibs, outside_fib - nm->outside_fibs);
+ }
+ }
- nat44_ei_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index,
- !is_del);
+ 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;
}
int
-nat44_ei_interface_add_del_output_feature (u32 sw_if_index, u8 is_inside,
- int is_del)
+nat44_ei_add_output_interface (u32 sw_if_index)
{
nat44_ei_main_t *nm = &nat44_ei_main;
- nat44_ei_interface_t *i;
- nat44_ei_address_t *ap;
- nat44_ei_static_mapping_t *m;
+
nat44_ei_outside_fib_t *outside_fib;
- u32 fib_index =
- fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
+ nat44_ei_interface_t *i;
+ u32 fib_index;
+ int rv;
fail_if_disabled ();
- if (nm->static_mapping_only && !(nm->static_mapping_connection_tracking))
+ if (nat44_ei_get_interface (nm->interfaces, sw_if_index))
{
- nat44_ei_log_err ("error unsupported");
- return VNET_API_ERROR_UNSUPPORTED;
+ nat44_ei_log_err ("error interface already configured");
+ return VNET_API_ERROR_VALUE_EXIST;
}
- pool_foreach (i, nm->interfaces)
+ if (nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index))
{
- if (i->sw_if_index == sw_if_index)
- {
- nat44_ei_log_err ("error interface already configured");
- return VNET_API_ERROR_VALUE_EXIST;
- }
+ nat44_ei_log_err ("error interface already configured");
+ return VNET_API_ERROR_VALUE_EXIST;
}
- if (!is_inside)
+ if (nm->num_workers > 1)
{
- vec_foreach (outside_fib, nm->outside_fibs)
+ rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
+ if (rv)
{
- if (outside_fib->fib_index == fib_index)
- {
- if (is_del)
- {
- outside_fib->refcount--;
- if (!outside_fib->refcount)
- vec_del1 (nm->outside_fibs,
- outside_fib - nm->outside_fibs);
- }
- else
- outside_fib->refcount++;
- goto feature_set;
- }
+ return rv;
}
- if (!is_del)
+ rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1);
+ if (rv)
{
- vec_add2 (nm->outside_fibs, outside_fib, 1);
- outside_fib->refcount = 1;
- outside_fib->fib_index = fib_index;
+ return rv;
+ }
+ rv = vnet_feature_enable_disable (
+ "ip4-unicast", "nat44-ei-out2in-worker-handoff", sw_if_index, 1, 0, 0);
+ if (rv)
+ {
+ return rv;
+ }
+ rv = vnet_feature_enable_disable (
+ "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index, 1,
+ 0, 0);
+ if (rv)
+ {
+ return rv;
}
}
-
-feature_set:
- if (is_inside)
+ else
{
- int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
+ rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
if (rv)
- return rv;
- rv =
- ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
+ {
+ return rv;
+ }
+ rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1);
if (rv)
- return rv;
- rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-hairpin-dst",
- sw_if_index, !is_del, 0, 0);
+ {
+ return rv;
+ }
+ rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in",
+ sw_if_index, 1, 0, 0);
if (rv)
- return rv;
- rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-hairpin-src",
- sw_if_index, !is_del, 0, 0);
+ {
+ return rv;
+ }
+ rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output",
+ sw_if_index, 1, 0, 0);
if (rv)
- return rv;
- goto fq;
+ {
+ return rv;
+ }
+ }
+
+ nat_validate_interface_counters (nm, sw_if_index);
+
+ pool_get (nm->output_feature_interfaces, i);
+ i->sw_if_index = sw_if_index;
+ i->flags = 0;
+ i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
+ i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
+
+ fib_index =
+ fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
+ outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
+ if (outside_fib)
+ {
+ outside_fib->refcount++;
+ }
+ else
+ {
+ vec_add2 (nm->outside_fibs, outside_fib, 1);
+ outside_fib->fib_index = fib_index;
+ outside_fib->refcount = 1;
+ }
+
+ 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);
+
+ return 0;
+}
+
+int
+nat44_ei_del_output_interface (u32 sw_if_index)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+
+ nat44_ei_outside_fib_t *outside_fib;
+ nat44_ei_interface_t *i;
+ u32 fib_index;
+ int rv;
+
+ fail_if_disabled ();
+
+ i = nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index);
+ if (!i)
+ {
+ nat44_ei_log_err ("error interface couldn't be found");
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
}
if (nm->num_workers > 1)
{
- int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
+ rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
if (rv)
- return rv;
- rv =
- ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
+ {
+ return rv;
+ }
+ rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0);
if (rv)
- return rv;
- rv = vnet_feature_enable_disable ("ip4-unicast",
- "nat44-ei-out2in-worker-handoff",
- sw_if_index, !is_del, 0, 0);
+ {
+ return rv;
+ }
+ rv = vnet_feature_enable_disable (
+ "ip4-unicast", "nat44-ei-out2in-worker-handoff", sw_if_index, 0, 0, 0);
if (rv)
- return rv;
+ {
+ return rv;
+ }
rv = vnet_feature_enable_disable (
- "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index,
- !is_del, 0, 0);
+ "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index, 0,
+ 0, 0);
if (rv)
- return rv;
+ {
+ return rv;
+ }
}
else
{
- int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
+ rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
if (rv)
- return rv;
- rv =
- ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
+ {
+ return rv;
+ }
+ rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0);
if (rv)
- return rv;
+ {
+ return rv;
+ }
rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in",
- sw_if_index, !is_del, 0, 0);
+ sw_if_index, 0, 0, 0);
if (rv)
- return rv;
+ {
+ return rv;
+ }
rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output",
- sw_if_index, !is_del, 0, 0);
+ sw_if_index, 0, 0, 0);
if (rv)
- return rv;
+ {
+ return rv;
+ }
}
-fq:
- if (nm->fq_in2out_output_index == ~0 && nm->num_workers > 1)
- nm->fq_in2out_output_index =
- vlib_frame_queue_main_init (nm->in2out_output_node_index, 0);
+ pool_put (nm->output_feature_interfaces, i);
- if (nm->fq_out2in_index == ~0 && nm->num_workers > 1)
- nm->fq_out2in_index =
- vlib_frame_queue_main_init (nm->out2in_node_index, 0);
-
- pool_foreach (i, nm->output_feature_interfaces)
+ fib_index =
+ fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
+ outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
+ if (outside_fib)
{
- if (i->sw_if_index == sw_if_index)
+ outside_fib->refcount--;
+ if (!outside_fib->refcount)
{
- if (is_del)
- pool_put (nm->output_feature_interfaces, i);
- else
- return VNET_API_ERROR_VALUE_EXIST;
-
- goto fib;
+ vec_del1 (nm->outside_fibs, outside_fib - nm->outside_fibs);
}
}
+ 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;
+}
+
+int
+nat44_ei_add_del_output_interface (u32 sw_if_index, int is_del)
+{
if (is_del)
{
- nat44_ei_log_err ("error interface couldn't be found");
- return VNET_API_ERROR_NO_SUCH_ENTRY;
+ return nat44_ei_del_output_interface (sw_if_index);
}
-
- pool_get (nm->output_feature_interfaces, i);
- i->sw_if_index = sw_if_index;
- i->flags = 0;
- nat_validate_interface_counters (nm, sw_if_index);
- if (is_inside)
- i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
else
- i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
-
- /* Add/delete external addresses to FIB */
-fib:
- if (is_inside)
- return 0;
+ {
+ return nat44_ei_add_output_interface (sw_if_index);
+ }
+}
- vec_foreach (ap, nm->addresses)
- nat44_ei_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, !is_del);
+int
+nat44_ei_del_addresses ()
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_address_t *a, *vec;
+ int error = 0;
- pool_foreach (m, nm->static_mappings)
+ vec = vec_dup (nm->addresses);
+ vec_foreach (a, vec)
{
- if (!((nat44_ei_is_addr_only_static_mapping (m))) ||
- (m->local_addr.as_u32 == m->external_addr.as_u32))
- continue;
+ error = nat44_ei_del_address (a->addr, 0);
- nat44_ei_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index,
- !is_del);
+ if (error)
+ {
+ nat44_ei_log_err ("error occurred while removing adderess");
+ }
}
+ vec_free (vec);
+ vec_free (nm->addresses);
+ nm->addresses = 0;
- return 0;
+ vec_free (nm->auto_add_sw_if_indices);
+ nm->auto_add_sw_if_indices = 0;
+ return error;
}
int
-nat44_ei_plugin_disable ()
+nat44_ei_del_interfaces ()
{
nat44_ei_main_t *nm = &nat44_ei_main;
- nat44_ei_interface_t *i, *vec;
+ nat44_ei_interface_t *i, *pool;
int error = 0;
- // first unregister all nodes from interfaces
- vec = vec_dup (nm->interfaces);
- vec_foreach (i, vec)
+ pool = pool_dup (nm->interfaces);
+ pool_foreach (i, pool)
{
if (nat44_ei_interface_is_inside (i))
- error = nat44_ei_interface_add_del (i->sw_if_index, 1, 1);
+ {
+ error = nat44_ei_del_interface (i->sw_if_index, 1);
+ }
if (nat44_ei_interface_is_outside (i))
- error = nat44_ei_interface_add_del (i->sw_if_index, 0, 1);
+ {
+ error = nat44_ei_del_interface (i->sw_if_index, 0);
+ }
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");
}
}
- vec_free (vec);
+ pool_free (pool);
+ pool_free (nm->interfaces);
nm->interfaces = 0;
+ return error;
+}
- vec = vec_dup (nm->output_feature_interfaces);
- vec_foreach (i, vec)
- {
- if (nat44_ei_interface_is_inside (i))
- error =
- nat44_ei_interface_add_del_output_feature (i->sw_if_index, 1, 1);
- if (nat44_ei_interface_is_outside (i))
- error =
- nat44_ei_interface_add_del_output_feature (i->sw_if_index, 0, 1);
+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)
+ {
+ 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");
}
}
- vec_free (vec);
+ 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));
+ nm->forwarding_enabled = 0;
+ nm->enabled = 0;
+
return error;
}
@@ -984,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);
@@ -995,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;
@@ -1044,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);
@@ -1058,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
@@ -1102,7 +1410,8 @@ nat44_ei_free_session_data_v2 (nat44_ei_main_t *nm, nat44_ei_session_t *s,
/* log NAT event */
nat_ipfix_logging_nat44_ses_delete (
thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
- s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index);
+ nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
+ s->in2out.fib_index);
nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
s->ext_host_port, s->nat_proto, s->out2in.fib_index,
@@ -1270,7 +1579,8 @@ nat44_ei_free_session_data (nat44_ei_main_t *nm, nat44_ei_session_t *s,
nat_ipfix_logging_nat44_ses_delete (
thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
- s->nat_proto, s->in2out.port, s->out2in.port, s->in2out.fib_index);
+ nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
+ s->in2out.fib_index);
nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
s->ext_host_port, s->nat_proto, s->out2in.fib_index,
@@ -1425,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)
{
@@ -1502,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;
}
@@ -1522,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);
@@ -1612,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:
@@ -1659,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:
@@ -1725,30 +2048,6 @@ nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length)
nm->psid_length = psid_length;
}
-static void
-nat44_ei_add_static_mapping_when_resolved (ip4_address_t l_addr, u16 l_port,
- u16 e_port, nat_protocol_t proto,
- u32 sw_if_index, u32 vrf_id,
- int addr_only, int identity_nat,
- u8 *tag)
-{
- nat44_ei_main_t *nm = &nat44_ei_main;
- nat44_ei_static_map_resolve_t *rp;
-
- vec_add2 (nm->to_resolve, rp, 1);
- clib_memset (rp, 0, sizeof (*rp));
-
- 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->addr_only = addr_only;
- rp->identity_nat = identity_nat;
- rp->tag = vec_dup (tag);
-}
-
void
nat44_ei_delete_session (nat44_ei_main_t *nm, nat44_ei_session_t *ses,
u32 thread_index)
@@ -1787,10 +2086,13 @@ nat44_ei_del_session (nat44_ei_main_t *nm, ip4_address_t *addr, u16 port,
{
nat44_ei_main_per_thread_data_t *tnm;
clib_bihash_kv_8_8_t kv, value;
- u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
+ u32 fib_index;
nat44_ei_session_t *s;
clib_bihash_8_8_t *t;
+ fail_if_disabled ();
+
+ fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
init_nat_k (&kv, *addr, port, fib_index, proto);
t = is_in ? &nm->in2out : &nm->out2in;
if (!clib_bihash_search_8_8 (t, &kv, &value))
@@ -1812,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)
@@ -1840,412 +2129,560 @@ nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index,
u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
if (is_add)
- fib_table_entry_update_one_path (
- fib_index, &prefix, nm->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);
+ {
+ fib_table_entry_update_one_path (fib_index, &prefix, nm->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);
+ }
else
- fib_table_entry_delete (fib_index, &prefix, nm->fib_src_low);
+ {
+ fib_table_entry_delete (fib_index, &prefix, nm->fib_src_low);
+ }
}
int
-nat44_ei_add_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
- u16 l_port, u16 e_port, nat_protocol_t proto,
- u32 sw_if_index, u32 vrf_id, u8 addr_only,
- u8 identity_nat, u8 *tag, u8 is_add)
+nat44_ei_reserve_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
{
+ u32 ti = nat44_ei_get_thread_idx_by_port (port);
nat44_ei_main_t *nm = &nat44_ei_main;
- nat44_ei_static_mapping_t *m = 0;
- clib_bihash_kv_8_8_t kv, value;
nat44_ei_address_t *a = 0;
- u32 fib_index = ~0;
- nat44_ei_interface_t *interface;
- nat44_ei_main_per_thread_data_t *tnm;
- nat44_ei_user_key_t u_key;
- nat44_ei_user_t *u;
- dlist_elt_t *head, *elt;
- u32 elt_index, head_index;
- u32 ses_index;
- u64 user_index;
- nat44_ei_session_t *s;
- nat44_ei_static_map_resolve_t *rp, *rp_match = 0;
- nat44_ei_lb_addr_port_t *local;
- u32 find = ~0;
int i;
- if (sw_if_index != ~0)
+ for (i = 0; i < vec_len (nm->addresses); i++)
{
- ip4_address_t *first_int_addr;
+ a = nm->addresses + i;
- for (i = 0; i < vec_len (nm->to_resolve); i++)
- {
- rp = nm->to_resolve + i;
- if (rp->sw_if_index != sw_if_index ||
- rp->l_addr.as_u32 != l_addr.as_u32 || rp->vrf_id != vrf_id ||
- rp->addr_only != addr_only)
- continue;
+ if (a->addr.as_u32 != addr.as_u32)
+ continue;
- if (!addr_only)
- {
- if ((rp->l_port != l_port && rp->e_port != e_port) ||
- rp->proto != proto)
- continue;
- }
+ if (nat44_ei_port_is_used (a, proto, port))
+ continue;
- rp_match = rp;
- break;
+ nat44_ei_port_get (a, proto, port);
+ if (port > 1024)
+ {
+ a->busy_ports[proto]++;
+ a->busy_ports_per_thread[proto][ti]++;
}
+ return 0;
+ }
- /* Might be already set... */
- first_int_addr = ip4_interface_first_address (
- nm->ip4_main, sw_if_index, 0 /* just want the address */);
+ return 1;
+}
- if (is_add)
- {
- if (rp_match)
- return VNET_API_ERROR_VALUE_EXIST;
+int
+nat44_ei_free_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
+{
+ u32 ti = nat44_ei_get_thread_idx_by_port (port);
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_address_t *a = 0;
+ int i;
- nat44_ei_add_static_mapping_when_resolved (
- l_addr, l_port, e_port, proto, sw_if_index, vrf_id, addr_only,
- identity_nat, tag);
+ for (i = 0; i < vec_len (nm->addresses); i++)
+ {
+ a = nm->addresses + i;
- /* DHCP resolution required? */
- if (!first_int_addr)
- return 0;
+ if (a->addr.as_u32 != addr.as_u32)
+ continue;
- e_addr.as_u32 = first_int_addr->as_u32;
- /* Identity mapping? */
- if (l_addr.as_u32 == 0)
- l_addr.as_u32 = e_addr.as_u32;
- }
- else
+ nat44_ei_port_put (a, proto, port);
+ if (port > 1024)
{
- if (!rp_match)
- return VNET_API_ERROR_NO_SUCH_ENTRY;
-
- vec_del1 (nm->to_resolve, i);
-
- if (!first_int_addr)
- return 0;
-
- e_addr.as_u32 = first_int_addr->as_u32;
- /* Identity mapping? */
- if (l_addr.as_u32 == 0)
- l_addr.as_u32 = e_addr.as_u32;
+ a->busy_ports[proto]--;
+ a->busy_ports_per_thread[proto][ti]--;
}
+ return 0;
}
- init_nat_k (&kv, e_addr, addr_only ? 0 : e_port, 0, addr_only ? 0 : proto);
- if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
- m = pool_elt_at_index (nm->static_mappings, value.value);
+ return 1;
+}
- if (is_add)
- {
- if (m)
- {
- // identity mapping for second vrf
- if (nat44_ei_is_identity_static_mapping (m))
- {
- pool_foreach (local, m->locals)
- {
- if (local->vrf_id == vrf_id)
- return VNET_API_ERROR_VALUE_EXIST;
- }
- pool_get (m->locals, local);
- local->vrf_id = vrf_id;
- local->fib_index = fib_table_find_or_create_and_lock (
- FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
- init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index,
- m->proto, 0, m - nm->static_mappings);
- clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1);
- return 0;
- }
- return VNET_API_ERROR_VALUE_EXIST;
- }
+void
+nat44_ei_add_resolve_record (ip4_address_t l_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_static_map_resolve_t *rp;
+ nat44_ei_main_t *nm = &nat44_ei_main;
- /* Convert VRF id to FIB index */
- if (vrf_id != ~0)
- {
- fib_index = fib_table_find_or_create_and_lock (
- FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
- }
- /* If not specified use inside VRF id from NAT44 plugin config */
- else
- {
- fib_index = nm->inside_fib_index;
- vrf_id = nm->inside_vrf_id;
- fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
- }
+ vec_add2 (nm->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);
+}
- if (!identity_nat)
- {
- init_nat_k (&kv, l_addr, addr_only ? 0 : l_port, fib_index,
- addr_only ? 0 : proto);
- if (!clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv,
- &value))
- return VNET_API_ERROR_VALUE_EXIST;
- }
+int
+nat44_ei_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
+ nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
+ u32 flags, int *out)
+{
+ nat44_ei_static_map_resolve_t *rp;
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ int i;
+
+ for (i = 0; i < vec_len (nm->to_resolve); i++)
+ {
+ rp = nm->to_resolve + i;
- /* Find external address in allocated addresses and reserve port for
- address and port pair mapping when dynamic translations enabled */
- if (!(addr_only || nm->static_mapping_only))
+ if (rp->sw_if_index == sw_if_index && rp->vrf_id == vrf_id)
{
- for (i = 0; i < vec_len (nm->addresses); i++)
+ if (is_sm_identity_nat (rp->flags) && is_sm_identity_nat (flags))
{
- if (nm->addresses[i].addr.as_u32 == e_addr.as_u32)
+ if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags)))
{
- a = nm->addresses + i;
- /* External port must be unused */
- switch (proto)
+ if (rp->e_port != e_port || rp->proto != proto)
{
-#define _(N, j, n, s) \
- case NAT_PROTOCOL_##N: \
- if (a->busy_##n##_port_refcounts[e_port]) \
- return VNET_API_ERROR_INVALID_VALUE; \
- ++a->busy_##n##_port_refcounts[e_port]; \
- if (e_port > 1024) \
- { \
- a->busy_##n##_ports++; \
- a->busy_##n##_ports_per_thread[nat44_ei_get_thread_idx_by_port ( \
- e_port)]++; \
- } \
- break;
- foreach_nat_protocol
-#undef _
- default : nat_elog_info (nm, "unknown protocol");
- return VNET_API_ERROR_INVALID_VALUE_2;
+ continue;
}
- break;
}
}
- /* External address must be allocated */
- if (!a && (l_addr.as_u32 != e_addr.as_u32))
+ else if (rp->l_addr.as_u32 == l_addr.as_u32)
{
- if (sw_if_index != ~0)
+ if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags)))
{
- for (i = 0; i < vec_len (nm->to_resolve); i++)
+ if (rp->l_port != l_port || rp->e_port != e_port ||
+ rp->proto != proto)
{
- rp = nm->to_resolve + i;
- if (rp->addr_only)
- continue;
- if (rp->sw_if_index != sw_if_index &&
- rp->l_addr.as_u32 != l_addr.as_u32 &&
- rp->vrf_id != vrf_id && rp->l_port != l_port &&
- rp->e_port != e_port && rp->proto != proto)
- continue;
-
- vec_del1 (nm->to_resolve, i);
- break;
+ continue;
}
}
- return VNET_API_ERROR_NO_SUCH_ENTRY;
}
+ else
+ {
+ continue;
+ }
+ if (out)
+ {
+ *out = i;
+ }
+ return 0;
}
+ }
+ return 1;
+}
- pool_get (nm->static_mappings, m);
- clib_memset (m, 0, sizeof (*m));
- m->tag = vec_dup (tag);
- m->local_addr = l_addr;
- m->external_addr = e_addr;
+int
+nat44_ei_del_resolve_record (ip4_address_t l_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;
+ int i;
+ if (!nat44_ei_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
+ sw_if_index, flags, &i))
+ {
+ vec_del1 (nm->to_resolve, i);
+ return 0;
+ }
+ return 1;
+}
- if (addr_only)
- m->flags |= NAT44_EI_STATIC_MAPPING_FLAG_ADDR_ONLY;
- else
+void
+delete_matching_dynamic_sessions (const nat44_ei_static_mapping_t *m,
+ u32 worker_index)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ clib_bihash_kv_8_8_t kv, value;
+ nat44_ei_session_t *s;
+ nat44_ei_user_key_t u_key;
+ nat44_ei_user_t *u;
+ nat44_ei_main_per_thread_data_t *tnm;
+ dlist_elt_t *head, *elt;
+ u32 elt_index, head_index;
+ u32 ses_index;
+ u64 user_index;
+
+ if (nm->static_mapping_only)
+ return;
+
+ tnm = vec_elt_at_index (nm->per_thread_data, worker_index);
+
+ u_key.addr = m->local_addr;
+ u_key.fib_index = m->fib_index;
+ kv.key = u_key.as_u64;
+ if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
+ {
+ user_index = value.value;
+ u = pool_elt_at_index (tnm->users, user_index);
+ if (u->nsessions)
{
- m->local_port = l_port;
- m->external_port = e_port;
- m->proto = proto;
+ 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);
+ ses_index = elt->value;
+ while (ses_index != ~0)
+ {
+ s = pool_elt_at_index (tnm->sessions, ses_index);
+ elt = pool_elt_at_index (tnm->list_pool, elt->next);
+ ses_index = elt->value;
+
+ if (nat44_ei_is_session_static (s))
+ continue;
+
+ if (!is_sm_addr_only (m->flags) &&
+ s->in2out.port != m->local_port)
+ continue;
+
+ nat44_ei_free_session_data_v2 (nm, s, tnm - nm->per_thread_data,
+ 0);
+ nat44_ei_delete_session (nm, s, tnm - nm->per_thread_data);
+
+ if (!is_sm_addr_only (m->flags))
+ break;
+ }
}
+ }
+}
+
+int
+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;
- if (identity_nat)
+ if (is_sm_switch_address (flags))
+ {
+ if (!nat44_ei_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
+ sw_if_index, flags, 0))
{
- m->flags |= NAT44_EI_STATIC_MAPPING_FLAG_IDENTITY_NAT;
- pool_get (m->locals, local);
- local->vrf_id = vrf_id;
- local->fib_index = fib_index;
+ return VNET_API_ERROR_VALUE_EXIST;
}
- else
+
+ nat44_ei_add_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
+ sw_if_index, flags, pool_addr, tag);
+
+ ip4_address_t *first_int_addr =
+ ip4_interface_first_address (nm->ip4_main, sw_if_index, 0);
+ if (!first_int_addr)
{
- m->vrf_id = vrf_id;
- m->fib_index = fib_index;
+ // dhcp resolution required
+ return 0;
}
- if (nm->num_workers > 1)
+ 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))
{
- ip4_header_t ip = {
- .src_address = m->local_addr,
- };
- vec_add1 (m->workers,
- nat44_ei_get_in2out_worker_index (&ip, m->fib_index, 0));
- tnm = vec_elt_at_index (nm->per_thread_data, m->workers[0]);
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
}
- else
- tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers);
- init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0,
- m - nm->static_mappings);
- clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1);
+ 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;
+ }
- init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
- m - nm->static_mappings);
- clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 1);
+ e_addr.as_u32 = first_int_addr->as_u32;
+ }
- /* Delete dynamic sessions matching local address (+ local port) */
- // TODO: based on type of NAT EI/ED
- if (!(nm->static_mapping_only))
- {
- u_key.addr = m->local_addr;
- u_key.fib_index = m->fib_index;
- kv.key = u_key.as_u64;
- if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
- {
- user_index = value.value;
- u = pool_elt_at_index (tnm->users, user_index);
- if (u->nsessions)
- {
- 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);
- ses_index = elt->value;
- while (ses_index != ~0)
- {
- s = pool_elt_at_index (tnm->sessions, ses_index);
- elt = pool_elt_at_index (tnm->list_pool, elt->next);
- ses_index = elt->value;
+ return nat44_ei_del_static_mapping_internal (
+ l_addr, e_addr, l_port, e_port, proto, vrf_id, sw_if_index, flags);
+}
- if (nat44_ei_is_session_static (s))
- continue;
+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;
- if (!addr_only && s->in2out.port != m->local_port)
- continue;
+ fail_if_disabled ();
- nat44_ei_free_session_data_v2 (
- nm, s, tnm - nm->per_thread_data, 0);
- nat44_ei_delete_session (nm, s,
- tnm - nm->per_thread_data);
+ if (is_sm_addr_only (flags))
+ {
+ e_port = l_port = proto = 0;
+ }
- if (!addr_only)
- break;
- }
- }
+ if (is_sm_identity_nat (flags))
+ {
+ l_port = e_port;
+ l_addr.as_u32 = e_addr.as_u32;
+ }
+
+ // fib index 0
+ init_nat_k (&kv, e_addr, e_port, 0, proto);
+
+ if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
+ {
+ m = pool_elt_at_index (nm->static_mappings, value.value);
+ 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)
+ {
+ return VNET_API_ERROR_VALUE_EXIST;
}
}
+
+ pool_get (m->locals, local);
+
+ local->vrf_id = vrf_id;
+ local->fib_index = fib_table_find_or_create_and_lock (
+ FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
+
+ init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index,
+ m->proto, 0, m - nm->static_mappings);
+ clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1);
+
+ return 0;
+ }
+
+ if (vrf_id != ~0)
+ {
+ fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
+ nm->fib_src_low);
}
else
{
- if (!m)
+ // fallback to default vrf
+ vrf_id = nm->inside_vrf_id;
+ fib_index = nm->inside_fib_index;
+ fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
+ }
+
+ if (!is_sm_identity_nat (flags))
+ {
+ init_nat_k (&kv, l_addr, l_port, fib_index, proto);
+ if (!clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv, &value))
{
- if (sw_if_index != ~0)
- return 0;
- else
- return VNET_API_ERROR_NO_SUCH_ENTRY;
+ return VNET_API_ERROR_VALUE_EXIST;
}
+ }
- if (identity_nat)
+ if (!(is_sm_addr_only (flags) || nm->static_mapping_only))
+ {
+ if (nat44_ei_reserve_port (e_addr, e_port, proto))
{
- if (vrf_id == ~0)
- vrf_id = nm->inside_vrf_id;
-
- pool_foreach (local, m->locals)
+ // remove resolve record
+ if ((is_sm_switch_address (flags)) && !is_sm_identity_nat (flags))
{
- if (local->vrf_id == vrf_id)
- find = local - m->locals;
+ nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto,
+ vrf_id, sw_if_index, flags);
}
- if (find == ~0)
- return VNET_API_ERROR_NO_SUCH_ENTRY;
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+ }
+ }
+
+ pool_get (nm->static_mappings, m);
+ clib_memset (m, 0, sizeof (*m));
- local = pool_elt_at_index (m->locals, find);
- fib_index = local->fib_index;
- pool_put (m->locals, local);
+ m->flags = flags;
+ m->local_addr = l_addr;
+ m->external_addr = e_addr;
+
+ m->tag = vec_dup (tag);
+
+ if (!is_sm_addr_only (flags))
+ {
+ m->local_port = l_port;
+ m->external_port = e_port;
+ m->proto = proto;
+ }
+
+ if (is_sm_identity_nat (flags))
+ {
+ pool_get (m->locals, local);
+
+ local->vrf_id = vrf_id;
+ local->fib_index = fib_index;
+ }
+ else
+ {
+ m->vrf_id = vrf_id;
+ m->fib_index = fib_index;
+ }
+
+ init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0,
+ m - nm->static_mappings);
+ clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1);
+
+ init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
+ m - nm->static_mappings);
+ clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 1);
+
+ if (nm->num_workers > 1)
+ {
+ // store worker index for this record
+ ip4_header_t ip = {
+ .src_address = m->local_addr,
+ };
+ worker_index = nat44_ei_get_in2out_worker_index (&ip, m->fib_index, 0);
+ vec_add1 (m->workers, worker_index);
+ }
+ else
+ {
+ worker_index = nm->num_workers;
+ }
+ delete_matching_dynamic_sessions (m, worker_index);
+
+ if (is_sm_addr_only (flags))
+ {
+ nat44_ei_add_del_addr_to_fib_foreach_out_if (&e_addr, 1);
+ }
+
+ return 0;
+}
+
+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;
+ 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;
+ nat44_ei_user_key_t u_key;
+
+ 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;
+ l_addr.as_u32 = e_addr.as_u32;
+ }
+
+ // fib index 0
+ init_nat_k (&kv, e_addr, e_port, 0, proto);
+
+ if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
+ {
+ if (is_sm_switch_address (flags))
+ {
+ return 0;
}
- else
- fib_index = m->fib_index;
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+ }
+
+ m = pool_elt_at_index (nm->static_mappings, value.value);
- /* Free external address port */
- if (!(addr_only || nm->static_mapping_only))
+ if (is_sm_identity_nat (flags))
+ {
+ u8 found = 0;
+
+ if (vrf_id == ~0)
{
- for (i = 0; i < vec_len (nm->addresses); i++)
+ vrf_id = nm->inside_vrf_id;
+ }
+
+ pool_foreach (local, m->locals)
+ {
+ if (local->vrf_id == vrf_id)
{
- if (nm->addresses[i].addr.as_u32 == e_addr.as_u32)
- {
- a = nm->addresses + i;
- switch (proto)
- {
-#define _(N, j, n, s) \
- case NAT_PROTOCOL_##N: \
- --a->busy_##n##_port_refcounts[e_port]; \
- if (e_port > 1024) \
- { \
- a->busy_##n##_ports--; \
- a->busy_##n##_ports_per_thread[nat44_ei_get_thread_idx_by_port ( \
- e_port)]--; \
- } \
- break;
- foreach_nat_protocol
-#undef _
- default : return VNET_API_ERROR_INVALID_VALUE_2;
- }
- break;
- }
+ local = pool_elt_at_index (m->locals, local - m->locals);
+ fib_index = local->fib_index;
+ pool_put (m->locals, local);
+ found = 1;
}
}
+ if (!found)
+ {
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+ }
+ }
+ else
+ {
+ fib_index = m->fib_index;
+ }
+
+ if (!(is_sm_addr_only (flags) || nm->static_mapping_only))
+ {
+ if (nat44_ei_free_port (e_addr, e_port, proto))
+ {
+ return VNET_API_ERROR_INVALID_VALUE;
+ }
+ }
+ init_nat_k (&kv, l_addr, l_port, fib_index, proto);
+ clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 0);
+
+ if (!nm->static_mapping_only || nm->static_mapping_connection_tracking)
+ {
+ // delete sessions for static mapping
if (nm->num_workers > 1)
tnm = vec_elt_at_index (nm->per_thread_data, m->workers[0]);
else
tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers);
- init_nat_k (&kv, m->local_addr, m->local_port, fib_index, m->proto);
- clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 0);
-
- /* Delete session(s) for static mapping if exist */
- if (!(nm->static_mapping_only) ||
- (nm->static_mapping_only && nm->static_mapping_connection_tracking))
- {
- u_key.addr = m->local_addr;
- u_key.fib_index = fib_index;
- kv.key = u_key.as_u64;
- nat44_ei_static_mapping_del_sessions (nm, tnm, u_key, addr_only,
- e_addr, e_port);
- }
+ u_key.addr = m->local_addr;
+ u_key.fib_index = fib_index;
+ kv.key = u_key.as_u64;
+ nat44_ei_static_mapping_del_sessions (
+ nm, tnm, u_key, is_sm_addr_only (flags), e_addr, e_port);
+ }
- fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
- if (pool_elts (m->locals))
- return 0;
+ fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
- init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
+ if (!pool_elts (m->locals))
+ {
+ // this is last record remove all required stuff
+ // fib_index 0
+ init_nat_k (&kv, e_addr, e_port, 0, proto);
clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 0);
vec_free (m->tag);
vec_free (m->workers);
- /* Delete static mapping from pool */
pool_put (nm->static_mappings, m);
- }
- if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
- return 0;
-
- /* Add/delete external address to FIB */
- pool_foreach (interface, nm->interfaces)
- {
- if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo)
- continue;
-
- nat44_ei_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index,
- is_add);
- break;
+ if (is_sm_addr_only (flags) && !is_sm_identity_nat (flags))
+ {
+ nat44_ei_add_del_addr_to_fib_foreach_out_if (&e_addr, 0);
+ }
}
- pool_foreach (interface, nm->output_feature_interfaces)
- {
- if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo)
- continue;
- nat44_ei_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index,
- is_add);
- break;
- }
return 0;
}
@@ -2300,16 +2737,16 @@ nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port,
}
/* Address only mapping doesn't change port */
- if (nat44_ei_is_addr_only_static_mapping (m))
+ if (is_sm_addr_only (m->flags))
*mapping_port = match_port;
else
*mapping_port = port;
if (PREDICT_FALSE (is_addr_only != 0))
- *is_addr_only = nat44_ei_is_addr_only_static_mapping (m);
+ *is_addr_only = is_sm_addr_only (m->flags);
if (PREDICT_FALSE (is_identity_nat != 0))
- *is_identity_nat = nat44_ei_is_identity_static_mapping (m);
+ *is_identity_nat = is_sm_identity_nat (m->flags);
return 0;
}
@@ -2418,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;
@@ -2572,11 +2988,13 @@ nat44_ei_update_outside_fib (ip4_main_t *im, uword opaque, u32 sw_if_index,
}
int
-nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr, u32 vrf_id)
+nat44_ei_add_address (ip4_address_t *addr, u32 vrf_id)
{
- nat44_ei_address_t *ap;
- nat44_ei_interface_t *i;
+ nat44_ei_main_t *nm = &nat44_ei_main;
vlib_thread_main_t *tm = vlib_get_thread_main ();
+ nat44_ei_address_t *ap;
+
+ fail_if_disabled ();
/* Check if address already exists */
vec_foreach (ap, nm->addresses)
@@ -2590,137 +3008,49 @@ nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr, u32 vrf_id)
vec_add2 (nm->addresses, ap, 1);
+ ap->fib_index = ~0;
ap->addr = *addr;
- if (vrf_id != ~0)
- ap->fib_index = fib_table_find_or_create_and_lock (
- FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
- else
- ap->fib_index = ~0;
-
-#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 _
- /* Add external address to FIB */
- pool_foreach (i, nm->interfaces)
- {
- if (nat44_ei_interface_is_inside (i) || nm->out2in_dpo)
- continue;
-
- nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
- break;
- }
- pool_foreach (i, nm->output_feature_interfaces)
+ if (vrf_id != ~0)
{
- if (nat44_ei_interface_is_inside (i) || nm->out2in_dpo)
- continue;
-
- nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
- break;
+ ap->fib_index = fib_table_find_or_create_and_lock (
+ FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
}
- return 0;
-}
-
-int
-nat44_ei_add_interface_address (nat44_ei_main_t *nm, u32 sw_if_index,
- int is_del)
-{
- ip4_main_t *ip4_main = nm->ip4_main;
- ip4_address_t *first_int_addr;
- nat44_ei_static_map_resolve_t *rp;
- u32 *indices_to_delete = 0;
- int i, j;
- u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices;
-
- first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
- 0 /* just want the address */);
-
- for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
+ nat_protocol_t proto;
+ for (proto = 0; proto < NAT_N_PROTOCOLS; ++proto)
{
- if (auto_add_sw_if_indices[i] == sw_if_index)
- {
- if (is_del)
- {
- /* if have address remove it */
- if (first_int_addr)
- (void) nat44_ei_del_address (nm, first_int_addr[0], 1);
- else
- {
- for (j = 0; j < vec_len (nm->to_resolve); j++)
- {
- rp = nm->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 (nm->to_resolve, j);
- vec_free (indices_to_delete);
- }
- }
- vec_del1 (nm->auto_add_sw_if_indices, i);
- }
- else
- return VNET_API_ERROR_VALUE_EXIST;
-
- return 0;
- }
+ 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);
}
- if (is_del)
- return VNET_API_ERROR_NO_SUCH_ENTRY;
-
- /* add to the auto-address list */
- vec_add1 (nm->auto_add_sw_if_indices, sw_if_index);
-
- /* If the address is already bound - or static - add it now */
- if (first_int_addr)
- (void) nat44_ei_add_address (nm, first_int_addr, ~0);
+ nat44_ei_add_del_addr_to_fib_foreach_out_if (addr, 1);
return 0;
}
-static int
-nat44_ei_is_address_used_in_static_mapping (ip4_address_t addr)
-{
- nat44_ei_main_t *nm = &nat44_ei_main;
- nat44_ei_static_mapping_t *m;
- pool_foreach (m, nm->static_mappings)
- {
- if (nat44_ei_is_addr_only_static_mapping (m) ||
- nat44_ei_is_identity_static_mapping (m))
- continue;
- if (m->external_addr.as_u32 == addr.as_u32)
- return 1;
- }
- return 0;
-}
-
int
-nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm)
+nat44_ei_del_address (ip4_address_t addr, u8 delete_sm)
{
+ nat44_ei_main_t *nm = &nat44_ei_main;
nat44_ei_address_t *a = 0;
nat44_ei_session_t *ses;
u32 *ses_to_be_removed = 0, *ses_index;
nat44_ei_main_per_thread_data_t *tnm;
- nat44_ei_interface_t *interface;
nat44_ei_static_mapping_t *m;
- int i;
+ int j;
+
+ fail_if_disabled ();
/* Find SNAT address */
- for (i = 0; i < vec_len (nm->addresses); i++)
+ for (j = 0; j < vec_len (nm->addresses); j++)
{
- if (nm->addresses[i].addr.as_u32 == addr.as_u32)
+ if (nm->addresses[j].addr.as_u32 == addr.as_u32)
{
- a = nm->addresses + i;
+ a = nm->addresses + j;
break;
}
}
@@ -2735,11 +3065,9 @@ nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm)
pool_foreach (m, nm->static_mappings)
{
if (m->external_addr.as_u32 == addr.as_u32)
- (void) nat44_ei_add_del_static_mapping (
+ nat44_ei_del_static_mapping_internal (
m->local_addr, m->external_addr, m->local_port, m->external_port,
- m->proto, ~0 /* sw_if_index */, m->vrf_id,
- nat44_ei_is_addr_only_static_mapping (m),
- nat44_ei_is_identity_static_mapping (m), m->tag, 0);
+ m->proto, m->vrf_id, ~0, m->flags);
}
}
else
@@ -2752,11 +3080,9 @@ nat44_ei_del_address (nat44_ei_main_t *nm, 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)
{
@@ -2778,28 +3104,116 @@ nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr, u8 delete_sm)
}
}
-#define _(N, i, n, s) vec_free (a->busy_##n##_ports_per_thread);
- foreach_nat_protocol
-#undef _
- vec_del1 (nm->addresses, i);
+ nat44_ei_add_del_addr_to_fib_foreach_out_if (&addr, 0);
- /* Delete external address from FIB */
- pool_foreach (interface, nm->interfaces)
+ if (a->fib_index != ~0)
{
- if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo)
- continue;
- nat44_ei_add_del_addr_to_fib (&addr, 32, interface->sw_if_index, 0);
- break;
+ fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
}
- pool_foreach (interface, nm->output_feature_interfaces)
+ nat_protocol_t proto;
+ for (proto = 0; proto < NAT_N_PROTOCOLS; ++proto)
{
- if (nat44_ei_interface_is_inside (interface) || nm->out2in_dpo)
- continue;
- nat44_ei_add_del_addr_to_fib (&addr, 32, interface->sw_if_index, 0);
- break;
+ vec_free (a->busy_ports_per_thread[proto]);
+ }
+
+ vec_del1 (nm->addresses, j);
+ return 0;
+}
+
+int
+nat44_ei_add_interface_address (u32 sw_if_index)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ ip4_main_t *ip4_main = nm->ip4_main;
+ ip4_address_t *first_int_addr;
+ u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices;
+ int i;
+
+ for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
+ {
+ if (auto_add_sw_if_indices[i] == sw_if_index)
+ {
+ return VNET_API_ERROR_VALUE_EXIST;
+ }
+ }
+
+ /* add to the auto-address list */
+ vec_add1 (nm->auto_add_sw_if_indices, sw_if_index);
+
+ // if the address is already bound - or static - add it now
+ first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
+ if (first_int_addr)
+ {
+ (void) nat44_ei_add_address (first_int_addr, ~0);
+ }
+
+ return 0;
+}
+
+int
+nat44_ei_del_interface_address (u32 sw_if_index)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ ip4_main_t *ip4_main = nm->ip4_main;
+ ip4_address_t *first_int_addr;
+ nat44_ei_static_map_resolve_t *rp;
+ u32 *indices_to_delete = 0;
+ int i, j;
+ u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices;
+
+ fail_if_disabled ();
+
+ first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
+
+ for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
+ {
+ 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)
+ {
+ (void) nat44_ei_del_address (first_int_addr[0], 1);
+ }
+ else
+ {
+ for (j = 0; j < vec_len (nm->to_resolve); j++)
+ {
+ rp = nm->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 (nm->to_resolve, j);
+ }
+ vec_free (indices_to_delete);
+ }
+ }
+
+ vec_del1 (nm->auto_add_sw_if_indices, i);
+ return 0;
+ }
}
+ return VNET_API_ERROR_NO_SUCH_ENTRY;
+}
+static_always_inline int
+is_sw_if_index_reg_for_auto_resolve (u32 *sw_if_indices, u32 sw_if_index)
+{
+ u32 *i;
+ vec_foreach (i, sw_if_indices)
+ {
+ if (*i == sw_if_index)
+ {
+ return 1;
+ }
+ }
return 0;
}
@@ -2812,61 +3226,59 @@ nat44_ei_ip4_add_del_interface_address_cb (ip4_main_t *im, uword opaque,
{
nat44_ei_main_t *nm = &nat44_ei_main;
nat44_ei_static_map_resolve_t *rp;
- ip4_address_t l_addr;
- int i, j;
- int rv;
nat44_ei_address_t *addresses = nm->addresses;
+ int rv, i;
if (!nm->enabled)
- return;
-
- for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++)
{
- if (sw_if_index == nm->auto_add_sw_if_indices[i])
- goto match;
+ return;
}
- return;
+ if (!is_sw_if_index_reg_for_auto_resolve (nm->auto_add_sw_if_indices,
+ sw_if_index))
+ {
+ return;
+ }
-match:
if (!is_delete)
{
/* Don't trip over lease renewal, static config */
- for (j = 0; j < vec_len (addresses); j++)
- if (addresses[j].addr.as_u32 == address->as_u32)
- return;
+ for (i = 0; i < vec_len (addresses); i++)
+ {
+ if (addresses[i].addr.as_u32 == address->as_u32)
+ {
+ return;
+ }
+ }
+
+ (void) nat44_ei_add_address (address, ~0);
- (void) nat44_ei_add_address (nm, address, ~0);
/* Scan static map resolution vector */
- for (j = 0; j < vec_len (nm->to_resolve); j++)
+ for (i = 0; i < vec_len (nm->to_resolve); i++)
{
- rp = nm->to_resolve + j;
- if (rp->addr_only)
- continue;
+ rp = nm->to_resolve + i;
+ if (is_sm_addr_only (rp->flags))
+ {
+ continue;
+ }
/* On this interface? */
if (rp->sw_if_index == sw_if_index)
{
- /* Indetity mapping? */
- if (rp->l_addr.as_u32 == 0)
- l_addr.as_u32 = address[0].as_u32;
- else
- l_addr.as_u32 = rp->l_addr.as_u32;
- /* Add the static mapping */
- rv = nat44_ei_add_del_static_mapping (
- l_addr, address[0], rp->l_port, rp->e_port, rp->proto,
- ~0 /* sw_if_index */, rp->vrf_id, rp->addr_only,
- rp->identity_nat, rp->tag, 1);
+ 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_del_static_mapping returned %d", "i4", rv);
+ {
+ nat_elog_notice_X1 (
+ nm, "add_static_mapping_internal returned %d", "i4", rv);
+ }
}
}
- return;
}
else
{
- (void) nat44_ei_del_address (nm, address[0], 1);
- return;
+ // remove all static mapping records
+ (void) nat44_ei_del_address (address[0], 1);
}
}
@@ -2889,57 +3301,64 @@ nat44_ei_ip4_add_del_addr_only_sm_cb (ip4_main_t *im, uword opaque,
nat44_ei_static_map_resolve_t *rp;
nat44_ei_static_mapping_t *m;
clib_bihash_kv_8_8_t kv, value;
- int i, rv;
- ip4_address_t l_addr;
+ int i, rv = 0, match = 0;
if (!nm->enabled)
- return;
+ {
+ return;
+ }
for (i = 0; i < vec_len (nm->to_resolve); i++)
{
rp = nm->to_resolve + i;
- if (rp->addr_only == 0)
- continue;
- if (rp->sw_if_index == sw_if_index)
- goto match;
+
+ if (is_sm_addr_only (rp->flags) && rp->sw_if_index == sw_if_index)
+ {
+ match = 1;
+ break;
+ }
}
- return;
+ if (!match)
+ {
+ return;
+ }
-match:
- init_nat_k (&kv, *address, rp->addr_only ? 0 : rp->e_port,
- nm->outside_fib_index, rp->addr_only ? 0 : rp->proto);
+ init_nat_k (&kv, *address, is_sm_addr_only (rp->flags) ? 0 : rp->e_port,
+ nm->outside_fib_index,
+ is_sm_addr_only (rp->flags) ? 0 : rp->proto);
if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
m = 0;
else
m = pool_elt_at_index (nm->static_mappings, value.value);
- if (!is_delete)
+ if (is_delete)
{
- /* Don't trip over lease renewal, static config */
- if (m)
+ if (!m)
return;
+ 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",
+ "i4", rv);
+ }
}
else
{
- if (!m)
+ if (m)
return;
- }
+ 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);
- /* Indetity mapping? */
- if (rp->l_addr.as_u32 == 0)
- l_addr.as_u32 = address[0].as_u32;
- else
- l_addr.as_u32 = rp->l_addr.as_u32;
- /* Add the static mapping */
-
- rv = nat44_ei_add_del_static_mapping (
- l_addr, address[0], rp->l_port, rp->e_port, rp->proto,
- ~0 /* sw_if_index */, rp->vrf_id, rp->addr_only, rp->identity_nat, rp->tag,
- !is_delete);
- if (rv)
- nat_elog_notice_X1 (nm, "nat44_ei_add_del_static_mapping returned %d",
- "i4", rv);
+ if (rv)
+ {
+ nat_elog_notice_X1 (nm, "nat44_ei_add_static_mapping returned %d",
+ "i4", rv);
+ }
+ }
}
static_always_inline uword
diff --git a/src/plugins/nat/nat44-ei/nat44_ei.h b/src/plugins/nat/nat44-ei/nat44_ei.h
index 055f81c069b..b4aa0f26c0b 100644
--- a/src/plugins/nat/nat44-ei/nat44_ei.h
+++ b/src/plugins/nat/nat44-ei/nat44_ei.h
@@ -36,6 +36,7 @@
#include <nat/lib/lib.h>
#include <nat/lib/inlines.h>
+#include <nat/lib/nat_proto.h>
/* default number of worker handoff frame queue elements */
#define NAT_FQ_NELTS_DEFAULT 64
@@ -62,19 +63,17 @@ typedef enum
#define NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO (1 << 1)
/* Static mapping flags */
-#define NAT44_EI_STATIC_MAPPING_FLAG_ADDR_ONLY (1 << 0)
-#define NAT44_EI_STATIC_MAPPING_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);
@@ -138,13 +137,9 @@ typedef struct
u32 vrf_id;
u32 flags;
nat_protocol_t proto;
- u8 addr_only;
- u8 identity_nat;
- u8 exact;
u8 *tag;
} nat44_ei_static_map_resolve_t;
-// TODO: cleanup/redo (there is no lb in EI nat)
typedef struct
{
/* backend IP address */
@@ -161,7 +156,7 @@ typedef struct
typedef struct
{
- /* prefered pool address */
+ /* preferred pool address */
ip4_address_t pool_addr;
/* local IP address */
ip4_address_t local_addr;
@@ -339,6 +334,8 @@ typedef struct nat44_ei_main_s
/* Interface pool */
nat44_ei_interface_t *interfaces;
nat44_ei_interface_t *output_feature_interfaces;
+ // broken api backward compatibility
+ nat44_ei_interface_t *output_feature_dummy_interfaces;
/* Is translation memory size calculated or user defined */
u8 translation_memory_size_set;
@@ -470,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;
@@ -483,9 +482,17 @@ typedef struct nat44_ei_main_s
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_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);
+int nat44_ei_del_interface_address (u32 sw_if_index);
+
/**
* @brief Delete specific NAT44 EI user and his sessions
*
@@ -532,29 +539,14 @@ void nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length);
*/
void nat44_ei_set_alloc_range (u16 start_port, u16 end_port);
-/**
- * @brief Add/delete NAT44-EI static mapping
- *
- * @param l_addr local IPv4 address
- * @param e_addr external IPv4 address
- * @param l_port local port number
- * @param e_port external port number
- * @param proto L4 protocol
- * @param sw_if_index use interface address as external IPv4 address
- * @param vrf_id local VRF ID
- * @param addr_only 1 = 1:1NAT, 0 = 1:1NAPT
- * @param identity_nat identity NAT
- * @param tag opaque string tag
- * @param is_add 1 = add, 0 = delete
- *
- * @return 0 on success, non-zero value otherwise
+int 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);
- */
-int nat44_ei_add_del_static_mapping (ip4_address_t l_addr,
- ip4_address_t e_addr, u16 l_port,
- u16 e_port, nat_protocol_t proto,
- u32 sw_if_index, u32 vrf_id, u8 addr_only,
- u8 identity_nat, u8 *tag, u8 is_add);
+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);
/**
* @brief Delete NAT44-EI session
@@ -619,9 +611,6 @@ int nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses,
ip4_address_t addr, u16 port,
nat_protocol_t protocol);
-int nat44_ei_del_address (nat44_ei_main_t *nm, ip4_address_t addr,
- u8 delete_sm);
-
void nat44_ei_free_session_data (nat44_ei_main_t *nm, nat44_ei_session_t *s,
u32 thread_index, u8 is_ha);
@@ -629,55 +618,56 @@ int nat44_ei_set_workers (uword *bitmap);
void nat44_ei_add_del_address_dpo (ip4_address_t addr, u8 is_add);
-int nat44_ei_add_address (nat44_ei_main_t *nm, ip4_address_t *addr,
- u32 vrf_id);
-
void nat44_ei_delete_session (nat44_ei_main_t *nm, nat44_ei_session_t *ses,
u32 thread_index);
-int nat44_ei_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del);
-
-int nat44_ei_interface_add_del_output_feature (u32 sw_if_index, u8 is_inside,
- int is_del);
-
-int nat44_ei_add_interface_address (nat44_ei_main_t *nm, u32 sw_if_index,
- int is_del);
-
/* Call back functions for clib_bihash_add_or_overwrite_stale */
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);
+int nat44_ei_set_frame_queue_nelts (u32 frame_queue_nelts);
-void nat44_ei_hairpinning_sm_unknown_proto (nat44_ei_main_t *nm,
- vlib_buffer_t *b,
- ip4_header_t *ip);
+always_inline bool
+nat44_ei_is_session_static (nat44_ei_session_t *s)
+{
+ return (s->flags & NAT44_EI_SESSION_FLAG_STATIC_MAPPING);
+}
-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);
+always_inline bool
+nat44_ei_is_unk_proto_session (nat44_ei_session_t *s)
+{
+ return (s->flags & NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO);
+}
-int nat44_ei_set_frame_queue_nelts (u32 frame_queue_nelts);
+always_inline bool
+nat44_ei_interface_is_inside (nat44_ei_interface_t *i)
+{
+ return (i->flags & NAT44_EI_INTERFACE_FLAG_IS_INSIDE);
+}
+
+always_inline bool
+nat44_ei_interface_is_outside (nat44_ei_interface_t *i)
+{
+ return (i->flags & NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE);
+}
-#define nat44_ei_is_session_static(sp) \
- (sp->flags & NAT44_EI_SESSION_FLAG_STATIC_MAPPING)
-#define nat44_ei_is_unk_proto_session(sp) \
- (sp->flags & NAT44_EI_SESSION_FLAG_UNKNOWN_PROTO)
+always_inline bool
+is_sm_addr_only (u32 f)
+{
+ return (f & NAT44_EI_SM_FLAG_ADDR_ONLY);
+}
-#define nat44_ei_interface_is_inside(ip) \
- (ip->flags & NAT44_EI_INTERFACE_FLAG_IS_INSIDE)
-#define nat44_ei_interface_is_outside(ip) \
- (ip->flags & NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE)
+always_inline bool
+is_sm_identity_nat (u32 f)
+{
+ return (f & NAT44_EI_SM_FLAG_IDENTITY_NAT);
+}
-#define nat44_ei_is_addr_only_static_mapping(mp) \
- (mp->flags & NAT44_EI_STATIC_MAPPING_FLAG_ADDR_ONLY)
-#define nat44_ei_is_identity_static_mapping(mp) \
- (mp->flags & NAT44_EI_STATIC_MAPPING_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(...) \
diff --git a/src/plugins/nat/nat44-ei/nat44_ei_api.c b/src/plugins/nat/nat44-ei/nat44_ei_api.c
index 427140ffb92..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);
}
@@ -469,9 +471,9 @@ vl_api_nat44_ei_add_del_address_range_t_handler (
for (i = 0; i < count; i++)
{
if (is_add)
- rv = nat44_ei_add_address (nm, &this_addr, vrf_id);
+ rv = nat44_ei_add_address (&this_addr, vrf_id);
else
- rv = nat44_ei_del_address (nm, this_addr, 0);
+ rv = nat44_ei_del_address (this_addr, 0);
if (rv)
goto send_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_interface_add_del (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);
}
@@ -588,19 +594,75 @@ vl_api_nat44_ei_interface_dump_t_handler (vl_api_nat44_ei_interface_dump_t *mp)
}
}
+static_always_inline int
+add_del_dummy_output_interface (u32 sw_if_index, u8 is_inside, u8 is_add)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ nat44_ei_interface_t *i;
+ int rv = 1;
+
+ pool_foreach (i, nm->output_feature_dummy_interfaces)
+ {
+ if (i->sw_if_index == sw_if_index)
+ {
+ if (!is_add)
+ {
+ pool_put (nm->output_feature_dummy_interfaces, i);
+ rv = 0;
+ }
+ goto done;
+ }
+ }
+
+ if (is_add)
+ {
+ pool_get (nm->output_feature_dummy_interfaces, i);
+ i->sw_if_index = sw_if_index;
+
+ if (is_inside)
+ {
+ i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
+ }
+ else
+ {
+ i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
+ }
+
+ rv = 0;
+ }
+
+done:
+ return rv;
+}
+
static void
vl_api_nat44_ei_interface_add_del_output_feature_t_handler (
vl_api_nat44_ei_interface_add_del_output_feature_t *mp)
{
- nat44_ei_main_t *nm = &nat44_ei_main;
vl_api_nat44_ei_interface_add_del_output_feature_reply_t *rmp;
- u32 sw_if_index = ntohl (mp->sw_if_index);
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ u32 sw_if_index;
int rv = 0;
VALIDATE_SW_IF_INDEX (mp);
- rv = nat44_ei_interface_add_del_output_feature (
- sw_if_index, mp->flags & NAT44_EI_IF_INSIDE, !mp->is_add);
+ 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 & NAT44_EI_IF_INSIDE, mp->is_add);
+
+ if (!(mp->flags & NAT44_EI_IF_INSIDE))
+ {
+ 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;
REPLY_MACRO (VL_API_NAT44_EI_INTERFACE_ADD_DEL_OUTPUT_FEATURE_REPLY);
@@ -622,7 +684,9 @@ send_nat44_ei_interface_output_feature_details (nat44_ei_interface_t *i,
rmp->context = context;
if (nat44_ei_interface_is_inside (i))
- rmp->flags |= NAT44_EI_IF_INSIDE;
+ {
+ rmp->flags |= NAT44_EI_IF_INSIDE;
+ }
vl_api_send_msg (reg, (u8 *) rmp);
}
@@ -639,49 +703,136 @@ vl_api_nat44_ei_interface_output_feature_dump_t_handler (
if (!reg)
return;
- pool_foreach (i, nm->output_feature_interfaces)
+ pool_foreach (i, nm->output_feature_dummy_interfaces)
{
send_nat44_ei_interface_output_feature_details (i, reg, mp->context);
}
}
static void
+vl_api_nat44_ei_add_del_output_interface_t_handler (
+ vl_api_nat44_ei_add_del_output_interface_t *mp)
+{
+ vl_api_nat44_ei_add_del_output_interface_reply_t *rmp;
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ int rv = 0;
+
+ VALIDATE_SW_IF_INDEX_END (mp);
+
+ 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:
+ REPLY_MACRO_END (VL_API_NAT44_EI_ADD_DEL_OUTPUT_INTERFACE_REPLY);
+}
+
+#define vl_endianfun
+#include <nat/nat44-ei/nat44_ei.api.h>
+#undef vl_endianfun
+static void
+send_nat44_ei_output_interface_details (u32 index, vl_api_registration_t *rp,
+ u32 context)
+{
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ vl_api_nat44_ei_output_interface_details_t *rmp;
+ nat44_ei_interface_t *i =
+ pool_elt_at_index (nm->output_feature_interfaces, index);
+
+ /* Make sure every field is initiated (or don't skip the clib_memset()) */
+ REPLY_MACRO_DETAILS4 (
+ VL_API_NAT44_EI_OUTPUT_INTERFACE_DETAILS, rp, context, ({
+ rmp->sw_if_index = i->sw_if_index;
+
+ /* Endian hack until apigen registers _details
+ * endian functions */
+ 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);
+ }));
+}
+
+static void
+vl_api_nat44_ei_output_interface_get_t_handler (
+ vl_api_nat44_ei_output_interface_get_t *mp)
+{
+ vl_api_nat44_ei_output_interface_get_reply_t *rmp;
+ nat44_ei_main_t *nm = &nat44_ei_main;
+ i32 rv = 0;
+
+ if (pool_elts (nm->output_feature_interfaces) == 0)
+ {
+ REPLY_MACRO (VL_API_NAT44_EI_OUTPUT_INTERFACE_GET_REPLY);
+ return;
+ }
+
+ REPLY_AND_DETAILS_MACRO (
+ VL_API_NAT44_EI_OUTPUT_INTERFACE_GET_REPLY, nm->output_feature_interfaces,
+ ({ send_nat44_ei_output_interface_details (cursor, rp, mp->context); }));
+}
+
+static void
vl_api_nat44_ei_add_del_static_mapping_t_handler (
vl_api_nat44_ei_add_del_static_mapping_t *mp)
{
- nat44_ei_main_t *nm = &nat44_ei_main;
vl_api_nat44_ei_add_del_static_mapping_reply_t *rmp;
- ip4_address_t local_addr, external_addr;
- u16 local_port = 0, external_port = 0;
- u32 vrf_id, external_sw_if_index;
+
+ nat44_ei_main_t *nm = &nat44_ei_main;
int rv = 0;
- nat_protocol_t proto;
+
+ ip4_address_t l_addr, e_addr, pool_addr = { 0 };
+ u32 sw_if_index, flags = 0, vrf_id;
+ u16 l_port = 0, e_port = 0;
+ nat_protocol_t proto = 0;
u8 *tag = 0;
- memcpy (&local_addr.as_u8, mp->local_ip_address, 4);
- memcpy (&external_addr.as_u8, mp->external_ip_address, 4);
+ memcpy (&l_addr.as_u8, mp->local_ip_address, 4);
- if (!(mp->flags & NAT44_EI_ADDR_ONLY_MAPPING))
+ if (mp->flags & NAT44_EI_ADDR_ONLY_MAPPING)
{
- local_port = mp->local_port;
- external_port = mp->external_port;
+ flags |= NAT44_EI_SM_FLAG_ADDR_ONLY;
+ }
+ else
+ {
+ l_port = mp->local_port;
+ e_port = mp->external_port;
+ proto = ip_proto_to_nat_proto (mp->protocol);
}
- vrf_id = clib_net_to_host_u32 (mp->vrf_id);
- external_sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index);
- proto = ip_proto_to_nat_proto (mp->protocol);
-
- mp->tag[sizeof (mp->tag) - 1] = 0;
- tag = format (0, "%s", mp->tag);
- vec_terminate_c_string (tag);
-
- rv = nat44_ei_add_del_static_mapping (
- local_addr, external_addr, local_port, external_port, proto,
- external_sw_if_index, vrf_id, mp->flags & NAT44_EI_ADDR_ONLY_MAPPING, 0,
- tag, mp->is_add);
+ sw_if_index = clib_net_to_host_u32 (mp->external_sw_if_index);
+ if (sw_if_index != ~0)
+ {
+ flags |= NAT44_EI_SM_FLAG_SWITCH_ADDRESS;
+ }
+ else
+ {
+ memcpy (&e_addr.as_u8, mp->external_ip_address, 4);
+ }
- vec_free (tag);
+ vrf_id = clib_net_to_host_u32 (mp->vrf_id);
+ if (mp->is_add)
+ {
+ mp->tag[sizeof (mp->tag) - 1] = 0;
+ tag = format (0, "%s", mp->tag);
+ vec_terminate_c_string (tag);
+
+ rv = nat44_ei_add_static_mapping (l_addr, e_addr, l_port, e_port, proto,
+ vrf_id, sw_if_index, flags, pool_addr,
+ tag);
+ vec_free (tag);
+ }
+ else
+ {
+ rv = nat44_ei_del_static_mapping (l_addr, e_addr, l_port, e_port, proto,
+ vrf_id, sw_if_index, flags);
+ }
REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_STATIC_MAPPING_REPLY);
}
@@ -704,7 +855,7 @@ send_nat44_ei_static_mapping_details (nat44_ei_static_mapping_t *m,
rmp->vrf_id = htonl (m->vrf_id);
rmp->context = context;
- if (nat44_ei_is_addr_only_static_mapping (m))
+ if (is_sm_addr_only (m->flags))
{
rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING;
}
@@ -738,7 +889,7 @@ send_nat44_ei_static_map_resolve_details (nat44_ei_static_map_resolve_t *m,
rmp->vrf_id = htonl (m->vrf_id);
rmp->context = context;
- if (m->addr_only)
+ if (is_sm_addr_only (m->flags))
{
rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING;
}
@@ -770,14 +921,14 @@ vl_api_nat44_ei_static_mapping_dump_t_handler (
pool_foreach (m, nm->static_mappings)
{
- if (!nat44_ei_is_identity_static_mapping (m))
+ if (!is_sm_identity_nat (m->flags))
send_nat44_ei_static_mapping_details (m, reg, mp->context);
}
for (j = 0; j < vec_len (nm->to_resolve); j++)
{
rp = nm->to_resolve + j;
- if (!rp->identity_nat)
+ if (!is_sm_identity_nat (rp->flags))
send_nat44_ei_static_map_resolve_details (rp, reg, mp->context);
}
}
@@ -786,35 +937,56 @@ static void
vl_api_nat44_ei_add_del_identity_mapping_t_handler (
vl_api_nat44_ei_add_del_identity_mapping_t *mp)
{
- nat44_ei_main_t *nm = &nat44_ei_main;
vl_api_nat44_ei_add_del_identity_mapping_reply_t *rmp;
- ip4_address_t addr;
- u16 port = 0;
- u32 vrf_id, sw_if_index;
+
+ nat44_ei_main_t *nm = &nat44_ei_main;
int rv = 0;
- nat_protocol_t proto = NAT_PROTOCOL_OTHER;
+
+ ip4_address_t addr, pool_addr = { 0 };
+ u32 sw_if_index, flags, vrf_id;
+ nat_protocol_t proto = 0;
+ u16 port = 0;
u8 *tag = 0;
- if (!(mp->flags & NAT44_EI_ADDR_ONLY_MAPPING))
+ flags = NAT44_EI_SM_FLAG_IDENTITY_NAT;
+
+ if (mp->flags & NAT44_EI_ADDR_ONLY_MAPPING)
+ {
+ flags |= NAT44_EI_SM_FLAG_ADDR_ONLY;
+ }
+ else
{
port = mp->port;
proto = ip_proto_to_nat_proto (mp->protocol);
}
- vrf_id = clib_net_to_host_u32 (mp->vrf_id);
+
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
- memcpy (&addr.as_u8, mp->ip_address, 4);
- mp->tag[sizeof (mp->tag) - 1] = 0;
- tag = format (0, "%s", mp->tag);
- vec_terminate_c_string (tag);
+ {
+ memcpy (&addr.as_u8, mp->ip_address, 4);
+ }
- rv = nat44_ei_add_del_static_mapping (
- addr, addr, port, port, proto, sw_if_index, vrf_id,
- mp->flags & NAT44_EI_ADDR_ONLY_MAPPING, 1, tag, mp->is_add);
+ vrf_id = clib_net_to_host_u32 (mp->vrf_id);
- vec_free (tag);
+ if (mp->is_add)
+ {
+ mp->tag[sizeof (mp->tag) - 1] = 0;
+ tag = format (0, "%s", mp->tag);
+ vec_terminate_c_string (tag);
+
+ rv = nat44_ei_add_static_mapping (addr, addr, port, port, proto, vrf_id,
+ sw_if_index, flags, pool_addr, tag);
+ vec_free (tag);
+ }
+ else
+ {
+ rv = nat44_ei_del_static_mapping (addr, addr, port, port, proto, vrf_id,
+ sw_if_index, flags);
+ }
REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_IDENTITY_MAPPING_REPLY);
}
@@ -833,7 +1005,7 @@ send_nat44_ei_identity_mapping_details (nat44_ei_static_mapping_t *m,
rmp->_vl_msg_id =
ntohs (VL_API_NAT44_EI_IDENTITY_MAPPING_DETAILS + nm->msg_id_base);
- if (nat44_ei_is_addr_only_static_mapping (m))
+ if (is_sm_addr_only (m->flags))
rmp->flags |= NAT44_EI_ADDR_ONLY_MAPPING;
clib_memcpy (rmp->ip_address, &(m->local_addr), 4);
@@ -860,7 +1032,7 @@ send_nat44_ei_identity_map_resolve_details (nat44_ei_static_map_resolve_t *m,
rmp->_vl_msg_id =
ntohs (VL_API_NAT44_EI_IDENTITY_MAPPING_DETAILS + nm->msg_id_base);
- if (m->addr_only)
+ if (is_sm_addr_only (m->flags))
rmp->flags = (vl_api_nat44_ei_config_flags_t) NAT44_EI_ADDR_ONLY_MAPPING;
rmp->port = m->l_port;
@@ -890,7 +1062,7 @@ vl_api_nat44_ei_identity_mapping_dump_t_handler (
pool_foreach (m, nm->static_mappings)
{
- if (nat44_ei_is_identity_static_mapping (m))
+ if (is_sm_identity_nat (m->flags))
{
pool_foreach_index (j, m->locals)
{
@@ -902,7 +1074,7 @@ vl_api_nat44_ei_identity_mapping_dump_t_handler (
for (j = 0; j < vec_len (nm->to_resolve); j++)
{
rp = nm->to_resolve + j;
- if (rp->identity_nat)
+ if (is_sm_identity_nat (rp->flags))
send_nat44_ei_identity_map_resolve_details (rp, reg, mp->context);
}
}
@@ -915,13 +1087,17 @@ vl_api_nat44_ei_add_del_interface_addr_t_handler (
vl_api_nat44_ei_add_del_interface_addr_reply_t *rmp;
u32 sw_if_index = ntohl (mp->sw_if_index);
int rv = 0;
- u8 is_del;
-
- is_del = !mp->is_add;
VALIDATE_SW_IF_INDEX (mp);
- rv = nat44_ei_add_interface_address (nm, sw_if_index, is_del);
+ if (mp->is_add)
+ {
+ rv = nat44_ei_add_interface_address (sw_if_index);
+ }
+ else
+ {
+ rv = nat44_ei_del_interface_address (sw_if_index);
+ }
BAD_SW_IF_INDEX_LABEL;
REPLY_MACRO (VL_API_NAT44_EI_ADD_DEL_INTERFACE_ADDR_REPLY);
@@ -1044,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)
{
@@ -1097,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 a009f0292d3..eab50a4bc6c 100644
--- a/src/plugins/nat/nat44-ei/nat44_ei_cli.c
+++ b/src/plugins/nat/nat44-ei/nat44_ei_cli.c
@@ -112,9 +112,9 @@ format_nat44_ei_static_mapping (u8 *s, va_list *args)
nat44_ei_static_mapping_t *m = va_arg (*args, nat44_ei_static_mapping_t *);
nat44_ei_lb_addr_port_t *local;
- if (nat44_ei_is_identity_static_mapping (m))
+ if (is_sm_identity_nat (m->flags))
{
- if (nat44_ei_is_addr_only_static_mapping (m))
+ if (is_sm_addr_only (m->flags))
s = format (s, "identity mapping %U", format_ip4_address,
&m->local_addr);
else
@@ -130,7 +130,7 @@ format_nat44_ei_static_mapping (u8 *s, va_list *args)
return s;
}
- if (nat44_ei_is_addr_only_static_mapping (m))
+ if (is_sm_addr_only (m->flags))
{
s = format (s, "local %U external %U vrf %d", format_ip4_address,
&m->local_addr, format_ip4_address, &m->external_addr,
@@ -154,7 +154,7 @@ format_nat44_ei_static_map_to_resolve (u8 *s, va_list *args)
va_arg (*args, nat44_ei_static_map_resolve_t *);
vnet_main_t *vnm = vnet_get_main ();
- if (m->addr_only)
+ if (is_sm_addr_only (m->flags))
s =
format (s, "local %U external %U vrf %d", format_ip4_address, &m->l_addr,
format_vnet_sw_if_index_name, vnm, m->sw_if_index, m->vrf_id);
@@ -312,7 +312,7 @@ done:
}
static clib_error_t *
-nat_show_workers_commnad_fn (vlib_main_t *vm, unformat_input_t *input,
+nat_show_workers_command_fn (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)
{
nat44_ei_main_t *nm = &nat44_ei_main;
@@ -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))
@@ -790,9 +790,9 @@ add_address_command_fn (vlib_main_t *vm, unformat_input_t *input,
for (i = 0; i < count; i++)
{
if (is_add)
- rv = nat44_ei_add_address (nm, &this_addr, vrf_id);
+ rv = nat44_ei_add_address (&this_addr, vrf_id);
else
- rv = nat44_ei_del_address (nm, this_addr, 0);
+ rv = nat44_ei_del_address (this_addr, 0);
switch (rv)
{
@@ -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,8 +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_interface_add_del_output_feature (sw_if_index, 1,
- 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",
@@ -905,7 +911,15 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input,
}
else
{
- if (nat44_ei_interface_add_del (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",
@@ -923,8 +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_interface_add_del_output_feature (sw_if_index, 0,
- 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",
@@ -934,7 +955,15 @@ nat44_ei_feature_command_fn (vlib_main_t *vm, unformat_input_t *input,
}
else
{
- if (nat44_ei_interface_add_del (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",
@@ -990,14 +1019,16 @@ add_static_mapping_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;
- ip4_address_t l_addr, e_addr;
- u32 l_port = 0, e_port = 0, vrf_id = ~0;
- int is_add = 1, addr_only = 1, rv;
- u32 sw_if_index = ~0;
vnet_main_t *vnm = vnet_get_main ();
+ clib_error_t *error = 0;
+ int rv;
+
nat_protocol_t proto = NAT_PROTOCOL_OTHER;
- u8 proto_set = 0;
+ ip4_address_t l_addr, e_addr, pool_addr = { 0 };
+ u32 l_port = 0, e_port = 0, vrf_id = ~0;
+ u8 l_port_set = 0, e_port_set = 0;
+ u32 sw_if_index = ~0, flags = 0;
+ int is_add = 1;
if (!unformat_user (input, unformat_line_input, line_input))
return clib_error_return (0, NAT44_EI_EXPECTED_ARGUMENT);
@@ -1006,29 +1037,37 @@ add_static_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
{
if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
&l_port))
- addr_only = 0;
+ {
+ l_port_set = 1;
+ }
else if (unformat (line_input, "local %U", unformat_ip4_address,
&l_addr))
;
else if (unformat (line_input, "external %U %u", unformat_ip4_address,
&e_addr, &e_port))
- addr_only = 0;
+ {
+ e_port_set = 1;
+ }
else if (unformat (line_input, "external %U", unformat_ip4_address,
&e_addr))
;
else if (unformat (line_input, "external %U %u",
unformat_vnet_sw_interface, vnm, &sw_if_index,
&e_port))
- addr_only = 0;
+ {
+ e_port_set = 1;
+ }
else if (unformat (line_input, "external %U", unformat_vnet_sw_interface,
vnm, &sw_if_index))
;
else if (unformat (line_input, "vrf %u", &vrf_id))
;
else if (unformat (line_input, "%U", unformat_nat_protocol, &proto))
- proto_set = 1;
+ ;
else if (unformat (line_input, "del"))
- is_add = 0;
+ {
+ is_add = 0;
+ }
else
{
error = clib_error_return (0, "unknown input: '%U'",
@@ -1037,25 +1076,38 @@ add_static_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
}
}
- if (addr_only)
+ if (l_port_set != e_port_set)
{
- if (proto_set)
- {
- error = clib_error_return (
- 0, "address only mapping doesn't support protocol");
- goto done;
- }
+ error = clib_error_return (0, "Either both ports are set or none.");
+ goto done;
}
- else if (!proto_set)
+
+ if (!l_port_set)
{
- error = clib_error_return (0, "protocol is required");
- goto done;
+ flags |= NAT44_EI_SM_FLAG_ADDR_ONLY;
+ }
+ else
+ {
+ l_port = clib_host_to_net_u16 (l_port);
+ e_port = clib_host_to_net_u16 (e_port);
+ }
+
+ if (sw_if_index != ~0)
+ {
+ flags |= NAT44_EI_SM_FLAG_SWITCH_ADDRESS;
}
- rv = nat44_ei_add_del_static_mapping (
- l_addr, e_addr, clib_host_to_net_u16 (l_port),
- clib_host_to_net_u16 (e_port), proto, sw_if_index, vrf_id, addr_only, 0, 0,
- is_add);
+ if (is_add)
+ {
+ rv =
+ nat44_ei_add_static_mapping (l_addr, e_addr, l_port, e_port, proto,
+ vrf_id, sw_if_index, flags, pool_addr, 0);
+ }
+ else
+ {
+ rv = nat44_ei_del_static_mapping (l_addr, e_addr, l_port, e_port, proto,
+ vrf_id, sw_if_index, flags);
+ }
switch (rv)
{
@@ -1091,17 +1143,15 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
+ vnet_main_t *vnm = vnet_get_main ();
clib_error_t *error = 0;
- u32 port = 0, vrf_id = ~0;
+
+ int rv, is_add = 1, port_set = 0;
+ u32 sw_if_index = ~0, port, flags, vrf_id = ~0;
+ nat_protocol_t proto = NAT_PROTOCOL_OTHER;
ip4_address_t addr;
- int is_add = 1;
- int addr_only = 1;
- u32 sw_if_index = ~0;
- vnet_main_t *vnm = vnet_get_main ();
- int rv;
- nat_protocol_t proto;
- addr.as_u32 = 0;
+ flags = NAT44_EI_SM_FLAG_IDENTITY_NAT;
if (!unformat_user (input, unformat_line_input, line_input))
return clib_error_return (0, NAT44_EI_EXPECTED_ARGUMENT);
@@ -1117,9 +1167,13 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
;
else if (unformat (line_input, "%U %u", unformat_nat_protocol, &proto,
&port))
- addr_only = 0;
+ {
+ port_set = 1;
+ }
else if (unformat (line_input, "del"))
- is_add = 0;
+ {
+ is_add = 0;
+ }
else
{
error = clib_error_return (0, "unknown input: '%U'",
@@ -1128,9 +1182,31 @@ add_identity_mapping_command_fn (vlib_main_t *vm, unformat_input_t *input,
}
}
- rv = nat44_ei_add_del_static_mapping (
- addr, addr, clib_host_to_net_u16 (port), clib_host_to_net_u16 (port),
- proto, sw_if_index, vrf_id, addr_only, 1, 0, is_add);
+ if (!port_set)
+ {
+ flags |= NAT44_EI_SM_FLAG_ADDR_ONLY;
+ }
+ else
+ {
+ port = clib_host_to_net_u16 (port);
+ }
+
+ if (sw_if_index != ~0)
+ {
+ flags |= NAT44_EI_SM_FLAG_SWITCH_ADDRESS;
+ }
+
+ if (is_add)
+ {
+
+ rv = nat44_ei_add_static_mapping (addr, addr, port, port, proto, vrf_id,
+ sw_if_index, flags, addr, 0);
+ }
+ else
+ {
+ rv = nat44_ei_del_static_mapping (addr, addr, port, port, proto, vrf_id,
+ sw_if_index, flags);
+ }
switch (rv)
{
@@ -1184,12 +1260,11 @@ nat44_ei_add_interface_address_command_fn (vlib_main_t *vm,
unformat_input_t *input,
vlib_cli_command_t *cmd)
{
- nat44_ei_main_t *nm = &nat44_ei_main;
unformat_input_t _line_input, *line_input = &_line_input;
- u32 sw_if_index;
- int rv;
- int is_del = 0;
+ nat44_ei_main_t *nm = &nat44_ei_main;
clib_error_t *error = 0;
+ int rv, is_del = 0;
+ u32 sw_if_index;
if (!unformat_user (input, unformat_line_input, line_input))
return clib_error_return (0, NAT44_EI_EXPECTED_ARGUMENT);
@@ -1200,7 +1275,9 @@ nat44_ei_add_interface_address_command_fn (vlib_main_t *vm,
nm->vnet_main, &sw_if_index))
;
else if (unformat (line_input, "del"))
- is_del = 1;
+ {
+ is_del = 1;
+ }
else
{
error = clib_error_return (0, "unknown input '%U'",
@@ -1209,17 +1286,21 @@ nat44_ei_add_interface_address_command_fn (vlib_main_t *vm,
}
}
- rv = nat44_ei_add_interface_address (nm, sw_if_index, is_del);
-
- switch (rv)
+ if (!is_del)
{
- case 0:
- break;
-
- default:
- error = clib_error_return (
- 0, "nat44_ei_add_interface_address returned %d", rv);
- goto done;
+ rv = nat44_ei_add_interface_address (sw_if_index);
+ if (rv)
+ {
+ error = clib_error_return (0, "add address returned %d", rv);
+ }
+ }
+ else
+ {
+ rv = nat44_ei_del_interface_address (sw_if_index);
+ if (rv)
+ {
+ error = clib_error_return (0, "del address returned %d", rv);
+ }
}
done:
@@ -1252,6 +1333,8 @@ nat44_ei_show_sessions_command_fn (vlib_main_t *vm, unformat_input_t *input,
{
unformat_input_t _line_input, *line_input = &_line_input;
clib_error_t *error = 0;
+ ip4_address_t saddr;
+ u8 filter_saddr = 0;
nat44_ei_main_per_thread_data_t *tnm;
nat44_ei_main_t *nm = &nat44_ei_main;
@@ -1266,6 +1349,9 @@ nat44_ei_show_sessions_command_fn (vlib_main_t *vm, unformat_input_t *input,
{
if (unformat (line_input, "detail"))
detail = 1;
+ else if (unformat (line_input, "filter saddr %U", unformat_ip4_address,
+ &saddr))
+ filter_saddr = 1;
else
{
error = clib_error_return (0, "unknown input '%U'",
@@ -1288,6 +1374,8 @@ print:
nat44_ei_user_t *u;
pool_foreach (u, tnm->users)
{
+ if (filter_saddr && saddr.as_u32 != u->addr.as_u32)
+ continue;
vlib_cli_output (vm, " %U", format_nat44_ei_user, tnm, u, detail);
}
}
@@ -1486,7 +1574,6 @@ nat_show_timeouts_command_fn (vlib_main_t *vm, unformat_input_t *input,
{
nat44_ei_main_t *nm = &nat44_ei_main;
- // TODO: make format timeout function
vlib_cli_output (vm, "udp timeout: %dsec", nm->timeouts.udp);
vlib_cli_output (vm, "tcp-established timeout: %dsec",
nm->timeouts.tcp.established);
@@ -1502,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,
@@ -1550,7 +1637,7 @@ VLIB_CLI_COMMAND (set_workers_command, static) = {
VLIB_CLI_COMMAND (nat_show_workers_command, static) = {
.path = "show nat44 ei workers",
.short_help = "show nat44 ei workers",
- .function = nat_show_workers_commnad_fn,
+ .function = nat_show_workers_command_fn,
};
/*?
@@ -1930,7 +2017,7 @@ VLIB_CLI_COMMAND (nat44_ei_show_interface_address_command, static) = {
?*/
VLIB_CLI_COMMAND (nat44_ei_show_sessions_command, static) = {
.path = "show nat44 ei sessions",
- .short_help = "show nat44 ei sessions [detail]",
+ .short_help = "show nat44 ei sessions [detail] [filter saddr <ip>]",
.function = nat44_ei_show_sessions_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_ha_doc.md b/src/plugins/nat/nat44-ei/nat44_ei_ha_doc.md
deleted file mode 100644
index f0ea209e250..00000000000
--- a/src/plugins/nat/nat44-ei/nat44_ei_ha_doc.md
+++ /dev/null
@@ -1,70 +0,0 @@
-# Active-Passive NAT HA {#nat_ha_doc}
-
-## Introduction
-
-One NAT node actively manages traffic while the other is synchronized and ready to transition to the active state and takes over seamlessly and enforces the same NAT sessions when failure occur. Both nodes share the same configuration settings.
-
-## Configuration
-
-### NAT HA protocol
-Session synchronization traffic is distributed through an IPv4 UDP connection. The active node sends NAT HA protocol events to passive node. To achieve reliable transfer NAT HA protocol uses acknowledgement with re-transmission. This require the passive node to respond with an acknowledgement message as it receives the data. The active node keeps a record of each packet it sends and maintains a timer from when the packet was sent. The active node re-transmits a packet if the timer expires before receiving the acknowledgement.
-
-### Topology
-
-The two NAT nodes have a dedicated link (interface GE0/0/3 on both) to synchronize NAT sessions using NAT HA protocol.
-
-```
- +-----------------------+
- | outside network |
- +-----------------------+
- / \
- / \
- / \
- / \
- / \
-+---------+ +---------+
-| GE0/0/1 | Active Passive | GE0/0/1 |
-| | | |
-| GE0/0/3|-------------------|GE0/0/3 |
-| | sync network | |
-| GE0/0/0 | | GE0/0/0 |
-+---------+ +---------+
- \ /
- \ /
- \ /
- \ /
- \ /
- +-----------------------+
- | inside network |
- +-----------------------+
-```
-
-### Active node configuration
-
-```
-set interface ip address GigabitEthernet0/0/1 10.15.7.101/24
-set interface ip address GigabitEthernet0/0/0 172.16.10.101/24
-set interface ip address GigabitEthernet0/0/3 10.0.0.1/24
-set interface state GigabitEthernet0/0/0 up
-set interface state GigabitEthernet0/0/1 up
-set interface state GigabitEthernet0/0/3 up
-set interface nat44 in GigabitEthernet0/0/0 out GigabitEthernet0/0/1
-nat44 add address 10.15.7.100
-nat ha listener 10.0.0.1:1234
-nat ha failover 10.0.0.2:2345
-```
-
-### Passive node configuration
-
-```
-set interface ip address GigabitEthernet0/0/1 10.15.7.102/24
-set interface ip address GigabitEthernet0/0/0 172.16.10.102/24
-set interface ip address GigabitEthernet0/0/3 10.0.0.2/24
-set interface state GigabitEthernet0/0/0 up
-set interface state GigabitEthernet0/0/1 up
-set interface state GigabitEthernet0/0/3 up
-set interface nat44 in GigabitEthernet0/0/0 out GigabitEthernet0/0/1
-nat44 add address 10.15.7.100
-nat ha listener 10.0.0.2:2345
-```
-
diff --git a/src/plugins/nat/nat44-ei/nat44_ei_ha_doc.rst b/src/plugins/nat/nat44-ei/nat44_ei_ha_doc.rst
new file mode 100644
index 00000000000..46befc52351
--- /dev/null
+++ b/src/plugins/nat/nat44-ei/nat44_ei_ha_doc.rst
@@ -0,0 +1,88 @@
+Active-Passive NAT HA
+=====================
+
+Introduction
+------------
+
+One NAT node actively manages traffic while the other is synchronized
+and ready to transition to the active state and takes over seamlessly
+and enforces the same NAT sessions when failure occur. Both nodes share
+the same configuration settings.
+
+Configuration
+-------------
+
+NAT HA protocol
+~~~~~~~~~~~~~~~
+
+Session synchronization traffic is distributed through an IPv4 UDP
+connection. The active node sends NAT HA protocol events to passive
+node. To achieve reliable transfer NAT HA protocol uses acknowledgment
+with re-transmission. This require the passive node to respond with an
+acknowledgment message as it receives the data. The active node keeps a
+record of each packet it sends and maintains a timer from when the
+packet was sent. The active node re-transmits a packet if the timer
+expires before receiving the acknowledgment.
+
+Topology
+~~~~~~~~
+
+The two NAT nodes have a dedicated link (interface GE0/0/3 on both) to
+synchronize NAT sessions using NAT HA protocol.
+
+::
+
+ +-----------------------+
+ | outside network |
+ +-----------------------+
+ / \
+ / \
+ / \
+ / \
+ / \
+ +---------+ +---------+
+ | GE0/0/1 | Active Passive | GE0/0/1 |
+ | | | |
+ | GE0/0/3|-------------------|GE0/0/3 |
+ | | sync network | |
+ | GE0/0/0 | | GE0/0/0 |
+ +---------+ +---------+
+ \ /
+ \ /
+ \ /
+ \ /
+ \ /
+ +-----------------------+
+ | inside network |
+ +-----------------------+
+
+Active node configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ set interface ip address GigabitEthernet0/0/1 10.15.7.101/24
+ set interface ip address GigabitEthernet0/0/0 172.16.10.101/24
+ set interface ip address GigabitEthernet0/0/3 10.0.0.1/24
+ set interface state GigabitEthernet0/0/0 up
+ set interface state GigabitEthernet0/0/1 up
+ set interface state GigabitEthernet0/0/3 up
+ set interface nat44 in GigabitEthernet0/0/0 out GigabitEthernet0/0/1
+ nat44 add address 10.15.7.100
+ nat ha listener 10.0.0.1:1234
+ nat ha failover 10.0.0.2:2345
+
+Passive node configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ set interface ip address GigabitEthernet0/0/1 10.15.7.102/24
+ set interface ip address GigabitEthernet0/0/0 172.16.10.102/24
+ set interface ip address GigabitEthernet0/0/3 10.0.0.2/24
+ set interface state GigabitEthernet0/0/0 up
+ set interface state GigabitEthernet0/0/1 up
+ set interface state GigabitEthernet0/0/3 up
+ set interface nat44 in GigabitEthernet0/0/0 out GigabitEthernet0/0/1
+ nat44 add address 10.15.7.100
+ nat ha listener 10.0.0.2:2345
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 a049e4659a7..00000000000
--- a/src/plugins/nat/nat44-ei/nat44_ei_hairpinning.c
+++ /dev/null
@@ -1,756 +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 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);
- sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-
- pool_foreach (i, nm->output_feature_interfaces)
- {
- /* Only packets from NAT inside interface */
- if ((nat44_ei_interface_is_inside (i)) &&
- (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, 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 c7a1317026b..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>
@@ -83,8 +82,6 @@ nat44_ei_worker_handoff_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_get_buffers (vm, from, b, n_left_from);
- // TODO: move to nm
- // TODO: remove callbacks and use inlines that should be moved here
if (is_in2out)
{
fq_index = is_output ? nm->fq_in2out_output_index : nm->fq_in2out_index;
diff --git a/src/plugins/nat/nat44-ei/nat44_ei_in2out.c b/src/plugins/nat/nat44-ei/nat44_ei_in2out.c
index 7ac1a92a61b..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)
@@ -271,13 +337,10 @@ nat44_i2o_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
if (clib_bihash_add_del_8_8 (&nm->out2in, &s_kv, 0))
nat_elog_warn (nm, "out2in key del failed");
- nat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
- s->in2out.addr.as_u32,
- s->out2in.addr.as_u32,
- s->nat_proto,
- s->in2out.port,
- s->out2in.port,
- s->in2out.fib_index);
+ nat_ipfix_logging_nat44_ses_delete (
+ ctx->thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
+ nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
+ s->in2out.fib_index);
nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
&s->in2out.addr, s->in2out.port,
@@ -430,8 +493,9 @@ slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_header_t *ip0,
/* log NAT event */
nat_ipfix_logging_nat44_ses_create (
- thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32, s->nat_proto,
- s->in2out.port, s->out2in.port, s->in2out.fib_index);
+ thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
+ nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
+ s->in2out.fib_index);
nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index, &s->in2out.addr,
s->in2out.port, &s->out2in.addr, s->out2in.port,
@@ -445,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)
@@ -490,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,
@@ -607,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,
@@ -676,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,
@@ -694,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;
@@ -856,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,
@@ -881,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)
@@ -913,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)
@@ -934,7 +1290,9 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
{
vlib_buffer_t *b0, *b1;
u32 next0, next1;
- u32 sw_if_index0, sw_if_index1;
+ u32 rx_sw_if_index0, rx_sw_if_index1;
+ u32 tx_sw_if_index0, tx_sw_if_index1;
+ u32 cntr_sw_if_index0, cntr_sw_if_index1;
ip4_header_t *ip0, *ip1;
ip_csum_t sum0, sum1;
u32 new_addr0, old_addr0, new_addr1, old_addr1;
@@ -978,13 +1336,16 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
tcp0 = (tcp_header_t *) udp0;
icmp0 = (icmp46_header_t *) udp0;
- sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ tx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
+ cntr_sw_if_index0 =
+ is_output_feature ? tx_sw_if_index0 : rx_sw_if_index0;
rx_fib_index0 =
- vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
+ vec_elt (nm->ip4_main->fib_index_by_sw_if_index, rx_sw_if_index0);
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,
@@ -1010,19 +1371,19 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (
is_slow_path ? &nm->counters.slowpath.in2out.other :
&nm->counters.fastpath.in2out.other,
- thread_index, sw_if_index0, 1);
+ thread_index, cntr_sw_if_index0, 1);
goto trace00;
}
if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
{
next0 = nat44_ei_icmp_in2out_slow_path (
- nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0,
- now, thread_index, &s0);
+ nm, b0, ip0, icmp0, rx_sw_if_index0, rx_fib_index0, node,
+ next0, now, thread_index, &s0);
vlib_increment_simple_counter (
is_slow_path ? &nm->counters.slowpath.in2out.icmp :
&nm->counters.fastpath.in2out.icmp,
- thread_index, sw_if_index0, 1);
+ thread_index, cntr_sw_if_index0, 1);
goto trace00;
}
}
@@ -1055,7 +1416,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
nm, ip0, proto0,
vnet_buffer (b0)->ip.reass.l4_src_port,
vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
- sw_if_index0)))
+ rx_sw_if_index0)))
goto trace00;
/*
@@ -1073,7 +1434,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
else
{
if (PREDICT_FALSE (nat44_ei_not_translate (
- nm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
+ nm, node, rx_sw_if_index0, ip0, proto0, rx_fib_index0,
thread_index)))
goto trace00;
}
@@ -1131,7 +1492,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (is_slow_path ?
&nm->counters.slowpath.in2out.tcp :
&nm->counters.fastpath.in2out.tcp,
- thread_index, sw_if_index0, 1);
+ thread_index, cntr_sw_if_index0, 1);
}
else
{
@@ -1155,7 +1516,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (is_slow_path ?
&nm->counters.slowpath.in2out.udp :
&nm->counters.fastpath.in2out.udp,
- thread_index, sw_if_index0, 1);
+ thread_index, cntr_sw_if_index0, 1);
}
/* Accounting */
@@ -1171,7 +1532,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
nat44_ei_in2out_trace_t *t =
vlib_add_trace (vm, node, b0, sizeof (*t));
t->is_slow_path = is_slow_path;
- t->sw_if_index = sw_if_index0;
+ t->sw_if_index = rx_sw_if_index0;
t->next_index = next0;
t->session_index = ~0;
if (s0)
@@ -1183,7 +1544,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (
is_slow_path ? &nm->counters.slowpath.in2out.drops :
&nm->counters.fastpath.in2out.drops,
- thread_index, sw_if_index0, 1);
+ thread_index, cntr_sw_if_index0, 1);
}
if (is_output_feature)
@@ -1196,11 +1557,14 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
tcp1 = (tcp_header_t *) udp1;
icmp1 = (icmp46_header_t *) udp1;
- sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+ rx_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+ tx_sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
+ cntr_sw_if_index1 =
+ is_output_feature ? tx_sw_if_index1 : rx_sw_if_index1;
rx_fib_index1 =
- vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_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,
@@ -1226,19 +1590,19 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (
is_slow_path ? &nm->counters.slowpath.in2out.other :
&nm->counters.fastpath.in2out.other,
- thread_index, sw_if_index1, 1);
+ thread_index, cntr_sw_if_index1, 1);
goto trace01;
}
if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
{
next1 = nat44_ei_icmp_in2out_slow_path (
- nm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, next1,
- now, thread_index, &s1);
+ nm, b1, ip1, icmp1, rx_sw_if_index1, rx_fib_index1, node,
+ next1, now, thread_index, &s1);
vlib_increment_simple_counter (
is_slow_path ? &nm->counters.slowpath.in2out.icmp :
&nm->counters.fastpath.in2out.icmp,
- thread_index, sw_if_index1, 1);
+ thread_index, cntr_sw_if_index1, 1);
goto trace01;
}
}
@@ -1271,7 +1635,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
nm, ip1, proto1,
vnet_buffer (b1)->ip.reass.l4_src_port,
vnet_buffer (b1)->ip.reass.l4_dst_port, thread_index,
- sw_if_index1)))
+ rx_sw_if_index1)))
goto trace01;
/*
@@ -1289,7 +1653,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
else
{
if (PREDICT_FALSE (nat44_ei_not_translate (
- nm, node, sw_if_index1, ip1, proto1, rx_fib_index1,
+ nm, node, rx_sw_if_index1, ip1, proto1, rx_fib_index1,
thread_index)))
goto trace01;
}
@@ -1346,7 +1710,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (is_slow_path ?
&nm->counters.slowpath.in2out.tcp :
&nm->counters.fastpath.in2out.tcp,
- thread_index, sw_if_index1, 1);
+ thread_index, cntr_sw_if_index1, 1);
}
else
{
@@ -1370,7 +1734,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (is_slow_path ?
&nm->counters.slowpath.in2out.udp :
&nm->counters.fastpath.in2out.udp,
- thread_index, sw_if_index1, 1);
+ thread_index, cntr_sw_if_index1, 1);
}
/* Accounting */
@@ -1385,7 +1749,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
{
nat44_ei_in2out_trace_t *t =
vlib_add_trace (vm, node, b1, sizeof (*t));
- t->sw_if_index = sw_if_index1;
+ t->sw_if_index = rx_sw_if_index1;
t->next_index = next1;
t->session_index = ~0;
if (s1)
@@ -1397,7 +1761,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (
is_slow_path ? &nm->counters.slowpath.in2out.drops :
&nm->counters.fastpath.in2out.drops,
- thread_index, sw_if_index1, 1);
+ thread_index, cntr_sw_if_index1, 1);
}
n_left_from -= 2;
@@ -1410,7 +1774,9 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
{
vlib_buffer_t *b0;
u32 next0;
- u32 sw_if_index0;
+ u32 rx_sw_if_index0;
+ u32 tx_sw_if_index0;
+ u32 cntr_sw_if_index0;
ip4_header_t *ip0;
ip_csum_t sum0;
u32 new_addr0, old_addr0;
@@ -1438,11 +1804,14 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
tcp0 = (tcp_header_t *) udp0;
icmp0 = (icmp46_header_t *) udp0;
- sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ rx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ tx_sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
+ cntr_sw_if_index0 =
+ is_output_feature ? tx_sw_if_index0 : rx_sw_if_index0;
rx_fib_index0 =
- vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_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,
@@ -1468,19 +1837,19 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (
is_slow_path ? &nm->counters.slowpath.in2out.other :
&nm->counters.fastpath.in2out.other,
- thread_index, sw_if_index0, 1);
+ thread_index, cntr_sw_if_index0, 1);
goto trace0;
}
if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
{
next0 = nat44_ei_icmp_in2out_slow_path (
- nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0,
- now, thread_index, &s0);
+ nm, b0, ip0, icmp0, rx_sw_if_index0, rx_fib_index0, node,
+ next0, now, thread_index, &s0);
vlib_increment_simple_counter (
is_slow_path ? &nm->counters.slowpath.in2out.icmp :
&nm->counters.fastpath.in2out.icmp,
- thread_index, sw_if_index0, 1);
+ thread_index, cntr_sw_if_index0, 1);
goto trace0;
}
}
@@ -1513,7 +1882,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
nm, ip0, proto0,
vnet_buffer (b0)->ip.reass.l4_src_port,
vnet_buffer (b0)->ip.reass.l4_dst_port, thread_index,
- sw_if_index0)))
+ rx_sw_if_index0)))
goto trace0;
/*
@@ -1531,7 +1900,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
else
{
if (PREDICT_FALSE (nat44_ei_not_translate (
- nm, node, sw_if_index0, ip0, proto0, rx_fib_index0,
+ nm, node, rx_sw_if_index0, ip0, proto0, rx_fib_index0,
thread_index)))
goto trace0;
}
@@ -1590,7 +1959,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (is_slow_path ?
&nm->counters.slowpath.in2out.tcp :
&nm->counters.fastpath.in2out.tcp,
- thread_index, sw_if_index0, 1);
+ thread_index, cntr_sw_if_index0, 1);
}
else
{
@@ -1615,7 +1984,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (is_slow_path ?
&nm->counters.slowpath.in2out.udp :
&nm->counters.fastpath.in2out.udp,
- thread_index, sw_if_index0, 1);
+ thread_index, cntr_sw_if_index0, 1);
}
/* Accounting */
@@ -1631,7 +2000,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
nat44_ei_in2out_trace_t *t =
vlib_add_trace (vm, node, b0, sizeof (*t));
t->is_slow_path = is_slow_path;
- t->sw_if_index = sw_if_index0;
+ t->sw_if_index = rx_sw_if_index0;
t->next_index = next0;
t->session_index = ~0;
if (s0)
@@ -1643,7 +2012,7 @@ nat44_ei_in2out_node_fn_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_increment_simple_counter (
is_slow_path ? &nm->counters.slowpath.in2out.drops :
&nm->counters.fastpath.in2out.drops,
- thread_index, sw_if_index0, 1);
+ thread_index, cntr_sw_if_index0, 1);
}
n_left_from--;
@@ -1656,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;
@@ -1802,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;
@@ -1824,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);
@@ -1832,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));
@@ -1951,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);
@@ -1971,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;
@@ -2064,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;
@@ -2081,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);
}
@@ -2145,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_inlines.h b/src/plugins/nat/nat44-ei/nat44_ei_inlines.h
index 672927256d1..399486c77dc 100644
--- a/src/plugins/nat/nat44-ei/nat44_ei_inlines.h
+++ b/src/plugins/nat/nat44-ei/nat44_ei_inlines.h
@@ -20,6 +20,7 @@
#include <nat/nat44-ei/nat44_ei.h>
#include <nat/nat44-ei/nat44_ei_ha.h>
+#include <nat/lib/nat_proto.h>
always_inline u64
calc_nat_key (ip4_address_t addr, u16 port, u32 fib_index, u8 proto)
@@ -220,6 +221,29 @@ nat44_ei_session_update_counters (nat44_ei_session_t *s, f64 now, uword bytes,
&s->ha_last_refreshed, now);
}
+static_always_inline u32
+nat_session_get_timeout (nat_timeouts_t *timeouts, nat_protocol_t proto,
+ u8 state)
+{
+ switch (proto)
+ {
+ case NAT_PROTOCOL_ICMP:
+ return timeouts->icmp;
+ case NAT_PROTOCOL_UDP:
+ return timeouts->udp;
+ case NAT_PROTOCOL_TCP:
+ {
+ if (state)
+ return timeouts->tcp.transitory;
+ else
+ return timeouts->tcp.established;
+ }
+ default:
+ return timeouts->udp;
+ }
+ return 0;
+}
+
#endif /* __included_nat44_ei_inlines_h__ */
/*
diff --git a/src/plugins/nat/nat44-ei/nat44_ei_out2in.c b/src/plugins/nat/nat44-ei/nat44_ei_out2in.c
index 7796b11cfd7..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") \
@@ -124,13 +112,10 @@ nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
if (clib_bihash_add_del_8_8 (&nm->in2out, &s_kv, 0))
nat_elog_warn (nm, "out2in key del failed");
- nat_ipfix_logging_nat44_ses_delete (ctx->thread_index,
- s->in2out.addr.as_u32,
- s->out2in.addr.as_u32,
- s->nat_proto,
- s->in2out.port,
- s->out2in.port,
- s->in2out.fib_index);
+ nat_ipfix_logging_nat44_ses_delete (
+ ctx->thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
+ nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
+ s->in2out.fib_index);
nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
&s->in2out.addr, s->in2out.port,
@@ -233,12 +218,10 @@ create_session_for_static_mapping (
nat_elog_notice (nm, "out2in key add failed");
/* log NAT event */
- nat_ipfix_logging_nat44_ses_create (thread_index,
- s->in2out.addr.as_u32,
- s->out2in.addr.as_u32,
- s->nat_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,
+ nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
+ s->in2out.fib_index);
nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
&s->in2out.addr, s->in2out.port, &s->out2in.addr,
@@ -1341,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),
@@ -1362,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