vcl session: propagate cleanup notifications to apps

Type: feature

Change-Id: I7f8e3763d7f8364563a25d0fcc782976b906b325
Signed-off-by: Florin Coras <fcoras@cisco.com>
diff --git a/src/plugins/hs_apps/sapi/vpp_echo.c b/src/plugins/hs_apps/sapi/vpp_echo.c
index 560c6a8..12be1f9 100644
--- a/src/plugins/hs_apps/sapi/vpp_echo.c
+++ b/src/plugins/hs_apps/sapi/vpp_echo.c
@@ -786,6 +786,12 @@
 }
 
 static void
+cleanup_handler (session_cleanup_msg_t * mp)
+{
+  ECHO_LOG (1, "Cleanup confirmed for 0x%lx", mp->handle);
+}
+
+static void
 handle_mq_event (session_event_t * e)
 {
   switch (e->event_type)
@@ -810,6 +816,9 @@
     case SESSION_CTRL_EVT_APP_DEL_SEGMENT:
       del_segment_handler ((session_app_del_segment_msg_t *) e->data);
       break;
+    case SESSION_CTRL_EVT_CLEANUP:
+      cleanup_handler ((session_cleanup_msg_t *) e->data);
+      break;
     case SESSION_IO_EVT_RX:
       break;
     default:
diff --git a/src/vcl/vcl_private.h b/src/vcl/vcl_private.h
index 30d3774..fd9d73c 100644
--- a/src/vcl/vcl_private.h
+++ b/src/vcl/vcl_private.h
@@ -375,6 +375,7 @@
 static inline void
 vcl_session_free (vcl_worker_t * wrk, vcl_session_t * s)
 {
+  VDBG (0, "session %u [0x%llx] removed", s->session_index, s->vpp_handle);
   pool_put (wrk->sessions, s);
 }
 
diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c
index 4b12062..916ddf9 100644
--- a/src/vcl/vppcom.c
+++ b/src/vcl/vppcom.c
@@ -713,6 +713,24 @@
 }
 
 static void
+vcl_session_cleanup_handler (vcl_worker_t * wrk, void *data)
+{
+  session_cleanup_msg_t *msg;
+  vcl_session_t *session;
+
+  msg = (session_cleanup_msg_t *) data;
+  session = vcl_session_get_w_vpp_handle (wrk, msg->handle);
+  if (!session)
+    {
+      VDBG (0, "disconnect confirmed for unknown handle 0x%llx", msg->handle);
+      return;
+    }
+
+  vcl_session_table_del_vpp_handle (wrk, msg->handle);
+  vcl_session_free (wrk, session);
+}
+
+static void
 vcl_session_req_worker_update_handler (vcl_worker_t * wrk, void *data)
 {
   session_req_worker_update_msg_t *msg;
@@ -845,6 +863,9 @@
     case SESSION_CTRL_EVT_MIGRATED:
       vcl_session_migrated_handler (wrk, e->data);
       break;
+    case SESSION_CTRL_EVT_CLEANUP:
+      vcl_session_cleanup_handler (wrk, e->data);
+      break;
     case SESSION_CTRL_EVT_REQ_WORKER_UPDATE:
       vcl_session_req_worker_update_handler (wrk, e->data);
       break;
@@ -1244,52 +1265,52 @@
 
 	  next_sh = session->vep.next_sh;
 	}
+      goto cleanup;
     }
-  else
+
+  if (session->is_vep_session)
     {
-      if (session->is_vep_session)
-	{
-	  rv = vppcom_epoll_ctl (vep_sh, EPOLL_CTL_DEL, sh, 0);
-	  if (rv < 0)
-	    VDBG (0, "session %u [0x%llx]: EPOLL_CTL_DEL vep_idx %u "
-		  "failed! rv %d (%s)", session->session_index, vpp_handle,
-		  vep_sh, rv, vppcom_retval_str (rv));
-	}
-
-      if (!do_disconnect)
-	{
-	  VDBG (1, "session %u [0x%llx] disconnect skipped",
-		session->session_index, vpp_handle);
-	  goto cleanup;
-	}
-
-      if (state & STATE_LISTEN)
-	{
-	  rv = vppcom_session_unbind (sh);
-	  if (PREDICT_FALSE (rv < 0))
-	    VDBG (0, "session %u [0x%llx]: listener unbind failed! "
-		  "rv %d (%s)", session->session_index, vpp_handle, rv,
-		  vppcom_retval_str (rv));
-	  return rv;
-	}
-      else if ((state & STATE_OPEN)
-	       || (vcl_session_is_connectable_listener (wrk, session)))
-	{
-	  rv = vppcom_session_disconnect (sh);
-	  if (PREDICT_FALSE (rv < 0))
-	    VDBG (0, "ERROR: session %u [0x%llx]: disconnect failed!"
-		  " rv %d (%s)", session->session_index, vpp_handle,
-		  rv, vppcom_retval_str (rv));
-	}
-      else if (state == STATE_DISCONNECT)
-	{
-	  svm_msg_q_t *mq = vcl_session_vpp_evt_q (wrk, session);
-	  vcl_send_session_reset_reply (mq, wrk->my_client_index,
-					session->vpp_handle, 0);
-	}
+      rv = vppcom_epoll_ctl (vep_sh, EPOLL_CTL_DEL, sh, 0);
+      if (rv < 0)
+	VDBG (0, "session %u [0x%llx]: EPOLL_CTL_DEL vep_idx %u "
+	      "failed! rv %d (%s)", session->session_index, vpp_handle,
+	      vep_sh, rv, vppcom_retval_str (rv));
     }
 
-  VDBG (0, "session %u [0x%llx] removed", session->session_index, vpp_handle);
+  if (!do_disconnect)
+    {
+      VDBG (1, "session %u [0x%llx] disconnect skipped",
+	    session->session_index, vpp_handle);
+      goto cleanup;
+    }
+
+  if (state & STATE_LISTEN)
+    {
+      rv = vppcom_session_unbind (sh);
+      if (PREDICT_FALSE (rv < 0))
+	VDBG (0, "session %u [0x%llx]: listener unbind failed! "
+	      "rv %d (%s)", session->session_index, vpp_handle, rv,
+	      vppcom_retval_str (rv));
+      return rv;
+    }
+  else if ((state & STATE_OPEN)
+	   || (vcl_session_is_connectable_listener (wrk, session)))
+    {
+      rv = vppcom_session_disconnect (sh);
+      if (PREDICT_FALSE (rv < 0))
+	VDBG (0, "ERROR: session %u [0x%llx]: disconnect failed!"
+	      " rv %d (%s)", session->session_index, vpp_handle,
+	      rv, vppcom_retval_str (rv));
+    }
+  else if (state == STATE_DISCONNECT)
+    {
+      svm_msg_q_t *mq = vcl_session_vpp_evt_q (wrk, session);
+      vcl_send_session_reset_reply (mq, wrk->my_client_index,
+				    session->vpp_handle, 0);
+    }
+
+  /* Session is removed only after vpp confirms the disconnect */
+  return rv;
 
 cleanup:
   vcl_session_table_del_vpp_handle (wrk, vpp_handle);
@@ -2163,6 +2184,9 @@
     case SESSION_CTRL_EVT_MIGRATED:
       vcl_session_migrated_handler (wrk, e->data);
       break;
+    case SESSION_CTRL_EVT_CLEANUP:
+      vcl_session_cleanup_handler (wrk, e->data);
+      break;
     case SESSION_CTRL_EVT_WORKER_UPDATE_REPLY:
       vcl_session_worker_update_reply_handler (wrk, e->data);
       break;
@@ -2774,6 +2798,9 @@
     case SESSION_CTRL_EVT_MIGRATED:
       vcl_session_migrated_handler (wrk, e->data);
       break;
+    case SESSION_CTRL_EVT_CLEANUP:
+      vcl_session_cleanup_handler (wrk, e->data);
+      break;
     case SESSION_CTRL_EVT_REQ_WORKER_UPDATE:
       vcl_session_req_worker_update_handler (wrk, e->data);
       break;
diff --git a/src/vnet/session/application_interface.h b/src/vnet/session/application_interface.h
index a664147..552fec1 100644
--- a/src/vnet/session/application_interface.h
+++ b/src/vnet/session/application_interface.h
@@ -510,6 +510,11 @@
   u32 vpp_thread_index;
 } __clib_packed session_migrated_msg_t;
 
+typedef struct session_cleanup_msg_
+{
+  session_handle_t handle;
+} __clib_packed session_cleanup_msg_t;
+
 typedef struct app_session_event_
 {
   svm_msg_q_msg_t msg;
diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c
index c6eeacf..a95faad 100644
--- a/src/vnet/session/session_api.c
+++ b/src/vnet/session/session_api.c
@@ -589,6 +589,35 @@
   return 0;
 }
 
+static void
+mq_send_session_cleanup_cb (session_t * s, session_cleanup_ntf_t ntf)
+{
+  svm_msg_q_msg_t _msg, *msg = &_msg;
+  session_cleanup_msg_t *mp;
+  svm_msg_q_t *app_mq;
+  session_event_t *evt;
+  app_worker_t *app_wrk;
+
+  /* Only propagate session cleanup notification */
+  if (ntf == SESSION_CLEANUP_TRANSPORT)
+    return;
+
+  app_wrk = app_worker_get_if_valid (s->app_wrk_index);
+  if (!app_wrk)
+    return;
+
+  app_mq = app_wrk->event_queue;
+  if (mq_try_lock_and_alloc_msg (app_mq, msg))
+    return;
+
+  evt = svm_msg_q_msg_data (app_mq, msg);
+  clib_memset (evt, 0, sizeof (*evt));
+  evt->event_type = SESSION_CTRL_EVT_CLEANUP;
+  mp = (session_cleanup_msg_t *) evt->data;
+  mp->handle = session_handle (s);
+  svm_msg_q_add_and_unlock (app_mq, msg);
+}
+
 /* ### WILL BE DEPRECATED POST 20.01 ### */
 static session_cb_vft_t session_mq_cb_vft_old = {
   .session_accept_callback = mq_send_session_accepted_cb,
@@ -606,6 +635,7 @@
   .session_connected_callback = mq_send_session_connected_cb,
   .session_reset_callback = mq_send_session_reset_cb,
   .session_migrate_callback = mq_send_session_migrate_cb,
+  .session_cleanup_callback = mq_send_session_cleanup_cb,
   .add_segment_callback = mq_send_add_segment_cb,
   .del_segment_callback = mq_send_del_segment_cb,
 };
diff --git a/src/vnet/session/session_types.h b/src/vnet/session/session_types.h
index 60d5e4d..be8ad9c 100644
--- a/src/vnet/session/session_types.h
+++ b/src/vnet/session/session_types.h
@@ -337,6 +337,7 @@
   SESSION_CTRL_EVT_APP_ADD_SEGMENT,
   SESSION_CTRL_EVT_APP_DEL_SEGMENT,
   SESSION_CTRL_EVT_MIGRATED,
+  SESSION_CTRL_EVT_CLEANUP,
 } session_evt_type_t;
 
 #define foreach_session_ctrl_evt				\
@@ -360,6 +361,8 @@
   _(APP_DETACH, app_detach)					\
   _(APP_ADD_SEGMENT, app_add_segment)				\
   _(APP_DEL_SEGMENT, app_del_segment)				\
+  _(MIGRATED, migrated)						\
+  _(CLEANUP, cleanup)						\
 
 /* Deprecated and will be removed. Use types above */
 #define FIFO_EVENT_APP_RX SESSION_IO_EVT_RX