+typedef struct cnat_trace_element_t_
+{
+ cnat_session_t session;
+ cnat_translation_t tr;
+ u32 sw_if_index[VLIB_N_RX_TX];
+ u32 snat_policy_result;
+ u8 flags;
+} cnat_trace_element_t;
+
+typedef enum cnat_trace_element_flag_t_
+{
+ CNAT_TRACE_SESSION_FOUND = (1 << 0),
+ CNAT_TRACE_SESSION_CREATED = (1 << 1),
+ CNAT_TRACE_TRANSLATION_FOUND = (1 << 2),
+ CNAT_TRACE_NO_NAT = (1 << 3),
+} cnat_trace_element_flag_t;
+
+static_always_inline void
+cnat_add_trace (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b,
+ cnat_session_t *session, const cnat_translation_t *ct,
+ u8 flags)
+{
+ cnat_trace_element_t *t;
+ if (NULL != ct)
+ flags |= CNAT_TRACE_TRANSLATION_FOUND;
+
+ t = vlib_add_trace (vm, node, b, sizeof (*t));
+ t->sw_if_index[VLIB_RX] = vnet_buffer (b)->sw_if_index[VLIB_RX];
+ t->sw_if_index[VLIB_TX] = vnet_buffer (b)->sw_if_index[VLIB_TX];
+
+ if (flags & (CNAT_TRACE_SESSION_FOUND | CNAT_TRACE_SESSION_CREATED))
+ clib_memcpy (&t->session, session, sizeof (t->session));
+ if (flags & CNAT_TRACE_TRANSLATION_FOUND)
+ clib_memcpy (&t->tr, ct, sizeof (cnat_translation_t));
+ t->flags = flags;
+}
+
+static u8 *
+format_cnat_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 *);
+ cnat_trace_element_t *t = va_arg (*args, cnat_trace_element_t *);
+ u32 indent = format_get_indent (s);
+ vnet_main_t *vnm = vnet_get_main ();
+
+ if (t->flags & CNAT_TRACE_SESSION_CREATED)
+ s = format (s, "created session");
+ else if (t->flags & CNAT_TRACE_SESSION_FOUND)
+ s = format (s, "found session");
+ else
+ s = format (s, "session not found");
+
+ if (t->flags & (CNAT_TRACE_NO_NAT))
+ s = format (s, " [policy:skip]");
+
+ s = format (s, "\n%Uin:%U out:%U ", format_white_space, indent,
+ format_vnet_sw_if_index_name, vnm, t->sw_if_index[VLIB_RX],
+ format_vnet_sw_if_index_name, vnm, t->sw_if_index[VLIB_TX]);
+
+ if (t->flags & (CNAT_TRACE_SESSION_CREATED | CNAT_TRACE_SESSION_FOUND))
+ s = format (s, "\n%U%U", format_white_space, indent, format_cnat_session,
+ &t->session, 1);
+
+ if (t->flags & CNAT_TRACE_TRANSLATION_FOUND)
+ s = format (s, "\n%Utranslation: %U", format_white_space, indent,
+ format_cnat_translation, &t->tr, 0);
+
+ return s;
+}
+