ikev2: cleanup stuck sessions

The following issues are fixed:
* in responder code: do lookup again as the old pointer could be
  invalidated during the cleanup operation
* in initiar code: do the cleanup of session if there're no child SAs or
  if there's no response from the responder during initial request (this
  can easily happen if the response packet was lost/dropped/etc)
* print the state of ikev2 profile (for easier tshooting)

Type: fix

Change-Id: I853d9851c0cf131696585e3c98fa97e66789badd
Signed-off-by: Stanislav Zaikin <stanislav.zaikin@46labs.com>
diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c
index f0eaa7a..3e80873 100644
--- a/src/plugins/ikev2/ikev2.c
+++ b/src/plugins/ikev2/ikev2.c
@@ -3269,6 +3269,8 @@
 	      if (sa0->state == IKEV2_STATE_AUTHENTICATED)
 		{
 		  ikev2_initial_contact_cleanup (ptd, sa0);
+		  p = hash_get (ptd->sa_by_rspi,
+				clib_net_to_host_u64 (ike0->rspi));
 		  ikev2_sa_match_ts (sa0);
 		  if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE)
 		    ikev2_create_tunnel_interface (vm, sa0, &sa0->childs[0],
@@ -5334,24 +5336,28 @@
           ikev2_child_sa_t *c;
           u8 del_old_ids = 0;
 
-          if (sa->state != IKEV2_STATE_AUTHENTICATED)
-            continue;
+	  if (sa->state == IKEV2_STATE_SA_INIT)
+	    {
+	      if (vec_len (sa->childs) > 0)
+		vec_add1 (to_be_deleted, sa - tkm->sas);
+	    }
+	  else if (sa->state != IKEV2_STATE_AUTHENTICATED)
+	    continue;
 
-          if (sa->old_remote_id_present && 0 > sa->old_id_expiration)
-            {
-              sa->old_remote_id_present = 0;
-              del_old_ids = 1;
-            }
-          else
-            sa->old_id_expiration -= 1;
+	  if (sa->old_remote_id_present && 0 > sa->old_id_expiration)
+	    {
+	      sa->old_remote_id_present = 0;
+	      del_old_ids = 1;
+	    }
+	  else
+	    sa->old_id_expiration -= 1;
 
-          vec_foreach (c, sa->childs)
-            ikev2_mngr_process_child_sa(sa, c, del_old_ids);
+	  vec_foreach (c, sa->childs)
+	    ikev2_mngr_process_child_sa (sa, c, del_old_ids);
 
-          if (!km->dpd_disabled && ikev2_mngr_process_responder_sas (sa))
-            vec_add1 (to_be_deleted, sa - tkm->sas);
-        }
-        /* *INDENT-ON* */
+	  if (!km->dpd_disabled && ikev2_mngr_process_responder_sas (sa))
+	    vec_add1 (to_be_deleted, sa - tkm->sas);
+	  }
 
 	vec_foreach (sai, to_be_deleted)
 	{
diff --git a/src/plugins/ikev2/ikev2_cli.c b/src/plugins/ikev2/ikev2_cli.c
index 382f1e1..285a899 100644
--- a/src/plugins/ikev2/ikev2_cli.c
+++ b/src/plugins/ikev2/ikev2_cli.c
@@ -121,6 +121,12 @@
   return s;
 }
 
+static char *stateNames[] = {
+#define _(v, f, s) s,
+  foreach_ikev2_state
+#undef _
+};
+
 static u8 *
 format_ikev2_sa (u8 * s, va_list * va)
 {
@@ -150,6 +156,11 @@
   tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH);
   s = format (s, "%U", format_ikev2_sa_transform, tr);
 
+  if (sa->state <= IKEV2_STATE_NO_PROPOSAL_CHOSEN)
+    {
+      s = format (s, "\n state: %s", stateNames[sa->state]);
+    }
+
   s = format (s, "\n%U", format_white_space, indent);
 
   s = format (s, "nonce i:%U\n%Ur:%U\n",
diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h
index faa0ca7..dca2fe8 100644
--- a/src/plugins/ikev2/ikev2_priv.h
+++ b/src/plugins/ikev2/ikev2_priv.h
@@ -184,16 +184,21 @@
 #define ikev2_log_debug(...) \
   vlib_log(VLIB_LOG_LEVEL_DEBUG, ikev2_main.log_class, __VA_ARGS__)
 
+#define foreach_ikev2_state                                                   \
+  _ (0, UNKNOWN, "UNKNOWN")                                                   \
+  _ (1, SA_INIT, "SA_INIT")                                                   \
+  _ (2, DELETED, "DELETED")                                                   \
+  _ (3, AUTH_FAILED, "AUTH_FAILED")                                           \
+  _ (4, AUTHENTICATED, "AUTHENTICATED")                                       \
+  _ (5, NOTIFY_AND_DELETE, "NOTIFY_AND_DELETE")                               \
+  _ (6, TS_UNACCEPTABLE, "TS_UNACCEPTABLE")                                   \
+  _ (7, NO_PROPOSAL_CHOSEN, "NO_PROPOSAL_CHOSEN")
+
 typedef enum
 {
-  IKEV2_STATE_UNKNOWN,
-  IKEV2_STATE_SA_INIT,
-  IKEV2_STATE_DELETED,
-  IKEV2_STATE_AUTH_FAILED,
-  IKEV2_STATE_AUTHENTICATED,
-  IKEV2_STATE_NOTIFY_AND_DELETE,
-  IKEV2_STATE_TS_UNACCEPTABLE,
-  IKEV2_STATE_NO_PROPOSAL_CHOSEN,
+#define _(v, f, s) IKEV2_STATE_##f = v,
+  foreach_ikev2_state
+#undef _
 } ikev2_state_t;
 
 typedef struct