vcl: store libc_epfd in vls instead of vcl

ldp stores the libc epfds it uses in conjunction with vcl epfds in vcl
attributes. Apart from being an ldp, as opposed to vcl, specific
attribute, the epfd is retrieved on session close with vls locks that
could be acquired from multiple threads.

Avoid grabbing locks when retrieving the attribute.

Type: improvement

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: I5fc52d72667a7693b1557d209c3890a968422f1e
diff --git a/src/vcl/vcl_locked.c b/src/vcl/vcl_locked.c
index 24cc598..9f3d6b5 100644
--- a/src/vcl/vcl_locked.c
+++ b/src/vcl/vcl_locked.c
@@ -103,6 +103,7 @@
   u32 shared_data_index;   /**< shared data index if any */
   u32 owner_vcl_wrk_index; /**< vcl wrk of the vls wrk at alloc */
   uword *vcl_wrk_index_to_session_index; /**< map vcl wrk to session */
+  int libc_epfd;			 /**< epoll fd for libc epoll */
 } vcl_locked_session_t;
 
 typedef struct vls_worker_
@@ -2028,6 +2029,52 @@
   return vcl_worker_get_current ()->vcl_needs_real_epoll;
 }
 
+int
+vls_set_libc_epfd (vls_handle_t ep_vlsh, int libc_epfd)
+{
+  vcl_locked_session_t *vls;
+
+  vls_mt_detect ();
+  if (!(vls = vls_get_w_dlock (ep_vlsh)))
+    return VPPCOM_EBADFD;
+  if (vls_mt_session_should_migrate (vls))
+    {
+      vls = vls_mt_session_migrate (vls);
+      if (PREDICT_FALSE (!vls))
+	return VPPCOM_EBADFD;
+    }
+  vls->libc_epfd = libc_epfd;
+  vls_unlock (vls);
+  vls_mt_pool_runlock ();
+  return 0;
+}
+
+int
+vls_get_libc_epfd (vls_handle_t ep_vlsh)
+{
+  vcl_locked_session_t *vls;
+  int rv;
+
+  vls_mt_detect ();
+  vls_mt_pool_rlock ();
+
+  vls = vls_get (ep_vlsh);
+  if (!vls)
+    {
+      vls_mt_pool_runlock ();
+      return VPPCOM_EBADFD;
+    }
+
+  /* Avoid locking. In mt scenarios, one thread might be blocking waiting on
+   * the fd while another might be closing it. While closing, this attribute
+   * might be retrieved, so avoid deadlock */
+  rv = vls->libc_epfd;
+
+  vls_mt_pool_runlock ();
+
+  return rv;
+}
+
 void
 vls_register_vcl_worker (void)
 {