#undef _
};
+typedef enum
+{
+ NAT_ED_SP_REASON_NO_REASON,
+ NAT_ED_SP_REASON_LOOKUP_FAILED,
+ NAT_ED_SP_REASON_VRF_EXPIRED,
+ NAT_ED_SP_TCP_CLOSED,
+ NAT_ED_SP_SESS_EXPIRED,
+} nat_slow_path_reason_e;
+
typedef struct
{
u32 sw_if_index;
u8 is_slow_path;
u8 translation_via_i2of;
u8 lookup_skipped;
+ nat_slow_path_reason_e slow_path_reason;
} nat44_ed_out2in_trace_t;
+static u8 *
+format_slow_path_reason (u8 *s, va_list *args)
+{
+ nat_slow_path_reason_e reason = va_arg (*args, nat_slow_path_reason_e);
+ switch (reason)
+ {
+ case NAT_ED_SP_REASON_NO_REASON:
+ return format (s, "no reason for slow path");
+ case NAT_ED_SP_REASON_LOOKUP_FAILED:
+ return format (s, "slow path because lookup failed");
+ case NAT_ED_SP_REASON_VRF_EXPIRED:
+ return format (s, "slow path because vrf expired");
+ case NAT_ED_SP_TCP_CLOSED:
+ return format (s, "slow path because tcp closed");
+ case NAT_ED_SP_SESS_EXPIRED:
+ return format (s, "slow path because session expired");
+ }
+ return format (s, "invalid reason value");
+}
+
static u8 *
format_nat44_ed_out2in_trace (u8 * s, va_list * args)
{
t->is_slow_path ? "NAT44_OUT2IN_ED_SLOW_PATH" :
"NAT44_OUT2IN_ED_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);
+ s = format (s, "%s: sw_if_index %d, next index %d", tag, t->sw_if_index,
+ t->next_index);
if (~0 != t->session_index)
{
- s = format (s, ", translation result '%U' via %s",
- format_nat_ed_translation_error, t->translation_error,
+ s = format (s, ", session %d, translation result '%U' via %s",
+ t->session_index, format_nat_ed_translation_error,
+ t->translation_error,
t->translation_via_i2of ? "i2of" : "o2if");
s = format (s, "\n i2of %U", format_nat_6t_flow, &t->i2of);
s = format (s, "\n o2if %U", format_nat_6t_flow, &t->o2if);
s = format (s, "\n search key %U", format_ed_session_kvp,
&t->search_key);
}
+ s = format (s, "\n %U", format_slow_path_reason, t->slow_path_reason);
}
return s;
static int
next_src_nat (snat_main_t *sm, ip4_header_t *ip, u16 src_port, u16 dst_port,
- u32 thread_index, u32 rx_fib_index)
+ u32 rx_fib_index)
{
clib_bihash_kv_16_8_t kv, value;
}
else
{
- if (next_src_nat (sm, ip, lookup_sport, lookup_dport, thread_index,
- rx_fib_index))
+ if (next_src_nat (sm, ip, lookup_sport, lookup_dport, rx_fib_index))
{
next = NAT_NEXT_IN2OUT_ED_FAST_PATH;
}
s->flags |= SNAT_SESSION_FLAG_LOAD_BALANCING;
if (lb_nat == AFFINITY_LB_NAT)
s->flags |= SNAT_SESSION_FLAG_AFFINITY;
- s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
s->out2in.addr = o2i_addr;
s->out2in.port = o2i_port;
s->out2in.fib_index = o2i_fib_index;
snat_address_t *filter = 0;
// if exact address is specified use this address
- if (is_exact_address (mapping))
+ if (is_sm_exact_address (mapping->flags))
{
snat_address_t *ap;
vec_foreach (ap, sm->twice_nat_addresses)
s->in2out.port, &s->ext_host_nat_addr,
s->ext_host_nat_port, &s->out2in.addr, s->out2in.port,
&s->ext_host_addr, s->ext_host_port, s->nat_proto,
- is_twice_nat_session (s));
+ nat44_ed_is_twice_nat_session (s));
per_vrf_sessions_register_session (s, thread_index);
if (ip->protocol == IP_PROTOCOL_ICMP)
{
- if (nat_get_icmp_session_lookup_values (b, ip, &lookup_saddr,
- &lookup_sport, &lookup_daddr,
+ if (nat_get_icmp_session_lookup_values (b, ip, &lookup_daddr,
+ &lookup_sport, &lookup_saddr,
&lookup_dport, &lookup_protocol))
return;
}
s->ext_host_addr.as_u32 = ip->src_address.as_u32;
s->flags |= SNAT_SESSION_FLAG_UNKNOWN_PROTO;
s->flags |= SNAT_SESSION_FLAG_STATIC_MAPPING;
- s->flags |= SNAT_SESSION_FLAG_ENDPOINT_DEPENDENT;
s->out2in.addr.as_u32 = ip->dst_address.as_u32;
s->out2in.fib_index = rx_fib_index;
s->in2out.addr.as_u32 = m->local_addr.as_u32;
snat_session_t *s0 = 0;
clib_bihash_kv_16_8_t kv0, value0;
nat_translation_error_e translation_error = NAT_ED_TRNSL_ERR_SUCCESS;
+ nat_slow_path_reason_e slow_path_reason = NAT_ED_SP_REASON_NO_REASON;
nat_6t_flow_t *f = 0;
nat_6t_t lookup;
int lookup_skipped = 0;
vlib_prefetch_buffer_header (p2, LOAD);
- CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
+ clib_prefetch_load (p2->data);
}
next[0] = vnet_buffer2 (b0)->nat.arc_next;
if (clib_bihash_search_16_8 (&sm->flow_hash, &kv0, &value0))
{
// flow does not exist go slow path
+ slow_path_reason = NAT_ED_SP_REASON_LOOKUP_FAILED;
next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
goto trace0;
}
ed_value_get_session_index (&value0));
skip_lookup:
+ ASSERT (thread_index == s0->thread_index);
+
if (PREDICT_FALSE (per_vrf_sessions_is_expired (s0, thread_index)))
{
// session is closed, go slow path
nat_free_session_data (sm, s0, thread_index, 0);
nat_ed_session_delete (sm, s0, thread_index, 1);
+ slow_path_reason = NAT_ED_SP_REASON_VRF_EXPIRED;
next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
goto trace0;
}
if (now >= s0->tcp_closed_timestamp)
{
// session is closed, go slow path, freed in slow path
+ slow_path_reason = NAT_ED_SP_TCP_CLOSED;
next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
}
else
// session is closed, go slow path
nat_free_session_data (sm, s0, thread_index, 0);
nat_ed_session_delete (sm, s0, thread_index, 1);
+ slow_path_reason = NAT_ED_SP_SESS_EXPIRED;
next[0] = NAT_NEXT_OUT2IN_ED_SLOW_PATH;
goto trace0;
}
nat_free_session_data (sm, s0, thread_index, 0);
nat_ed_session_delete (sm, s0, thread_index, 1);
next[0] = NAT_NEXT_DROP;
+ b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TRNSL_FAILED];
goto trace0;
}
}
}
if (NAT_ED_TRNSL_ERR_SUCCESS !=
- (translation_error = nat_6t_flow_buf_translate (
- sm, b0, ip0, f, proto0, 0 /* is_output_feature */)))
+ (translation_error = nat_6t_flow_buf_translate_o2i (
+ vm, sm, b0, ip0, f, proto0, 0 /* is_output_feature */)))
{
next[0] = NAT_NEXT_DROP;
+ b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TRNSL_FAILED];
goto trace0;
}
t->translation_error = translation_error;
clib_memcpy (&t->search_key, &kv0, sizeof (t->search_key));
t->lookup_skipped = lookup_skipped;
+ t->slow_path_reason = slow_path_reason;
if (s0)
{
if (!s0)
next[0] = NAT_NEXT_DROP;
}
- if (NAT_NEXT_DROP != next[0] &&
+ if (NAT_NEXT_DROP != next[0] && s0 &&
NAT_ED_TRNSL_ERR_SUCCESS !=
- (translation_error = nat_6t_flow_buf_translate (
- sm, b0, ip0, &s0->o2i, proto0, 0 /* is_output_feature */)))
+ (translation_error = nat_6t_flow_buf_translate_o2i (
+ vm, sm, b0, ip0, &s0->o2i, proto0,
+ 0 /* is_output_feature */)))
{
+ next[0] = NAT_NEXT_DROP;
+ b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TRNSL_FAILED];
goto trace0;
}
if (NAT_NEXT_DROP != next[0] && s0 &&
NAT_ED_TRNSL_ERR_SUCCESS !=
- (translation_error = nat_6t_flow_buf_translate (
- sm, b0, ip0, &s0->o2i, proto0, 0 /* is_output_feature */)))
+ (translation_error = nat_6t_flow_buf_translate_o2i (
+ vm, sm, b0, ip0, &s0->o2i, proto0,
+ 0 /* is_output_feature */)))
{
+ next[0] = NAT_NEXT_DROP;
+ b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TRNSL_FAILED];
goto trace0;
}
}
else
{
- if (next_src_nat
- (sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
- vnet_buffer (b0)->ip.reass.l4_dst_port,
- thread_index, rx_fib_index0))
+ if (next_src_nat (
+ sm, ip0, vnet_buffer (b0)->ip.reass.l4_src_port,
+ vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0))
{
next[0] = NAT_NEXT_IN2OUT_ED_FAST_PATH;
}
}
if (NAT_ED_TRNSL_ERR_SUCCESS !=
- (translation_error = nat_6t_flow_buf_translate (
- sm, b0, ip0, &s0->o2i, proto0, 0 /* is_output_feature */)))
+ (translation_error = nat_6t_flow_buf_translate_o2i (
+ vm, sm, b0, ip0, &s0->o2i, proto0, 0 /* is_output_feature */)))
{
next[0] = NAT_NEXT_DROP;
goto trace0;
}
}
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE (nat44_ed_out2in_node) = {
.name = "nat44-ed-out2in",
.vector_size = sizeof (u32),
.error_strings = nat_out2in_ed_error_strings,
.runtime_data_bytes = sizeof (snat_runtime_t),
};
-/* *INDENT-ON* */
VLIB_NODE_FN (nat44_ed_out2in_slowpath_node) (vlib_main_t * vm,
vlib_node_runtime_t * node,
return nat44_ed_out2in_slow_path_node_fn_inline (vm, node, frame);
}
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE (nat44_ed_out2in_slowpath_node) = {
.name = "nat44-ed-out2in-slowpath",
.vector_size = sizeof (u32),
.error_strings = nat_out2in_ed_error_strings,
.runtime_data_bytes = sizeof (snat_runtime_t),
};
-/* *INDENT-ON* */
static u8 *
format_nat_pre_trace (u8 * s, va_list * args)
NAT_NEXT_OUT2IN_ED_FAST_PATH);
}
-/* *INDENT-OFF* */
VLIB_REGISTER_NODE (nat_pre_out2in_node) = {
.name = "nat-pre-out2in",
.vector_size = sizeof (u32),
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = 0,
};
-/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON