static void
vls_listener_wrk_start_listen (vcl_locked_session_t * vls, u32 wrk_index)
{
- vppcom_session_listen (vls_to_sh (vls), ~0);
- vls_listener_wrk_set (vls, wrk_index, 1 /* is_active */ );
+ vcl_worker_t *wrk;
+ vcl_session_t *ls;
+
+ wrk = vcl_worker_get (wrk_index);
+ ls = vcl_session_get (wrk, vls->session_index);
+
+ /* Listen request already sent */
+ if (ls->flags & VCL_SESSION_F_PENDING_LISTEN)
+ return;
+
+ vcl_send_session_listen (wrk, ls);
+
+ vls_listener_wrk_set (vls, wrk_index, 1 /* is_active */);
}
static void
vls_listener_wrk_set (vls, vls->vcl_wrk_index, 1 /* is_active */);
break;
}
- vls_listener_wrk_stop_listen (vls, vls->vcl_wrk_index);
+ /* Although removal from epoll means listener no longer accepts new
+ * sessions, the accept queue built by vpp cannot be drained by stopping
+ * the listener. Morover, some applications, e.g., nginx, might
+ * constantly remove and add listeners to their epfds. Removing
+ * listeners in such situations causes a lot of churn in vpp as segments
+ * and segment managers need to be recreated. */
+ /* vls_listener_wrk_stop_listen (vls, vls->vcl_wrk_index); */
break;
case VCL_STATE_LISTEN_NO_MQ:
if (!is_add)
vls_mt_detect ();
vls_mt_pool_rlock ();
+
ep_vls = vls_get_and_lock (ep_vlsh);
+ if (PREDICT_FALSE (!ep_vls))
+ {
+ vls_mt_pool_runlock ();
+ return VPPCOM_EBADFD;
+ }
if (vls_mt_session_should_migrate (ep_vls))
{
ep_vls = vls_mt_session_migrate (ep_vls);
if (PREDICT_FALSE (!ep_vls))
- return VPPCOM_EBADFD;
+ {
+ vls_mt_pool_runlock ();
+ return VPPCOM_EBADFD;
+ }
}
- ep_sh = vls_to_sh (ep_vls);
vls = vls_get_and_lock (vlsh);
+ if (PREDICT_FALSE (!vls))
+ {
+ vls_unlock (ep_vls);
+ vls_mt_pool_runlock ();
+ return VPPCOM_EBADFD;
+ }
+
+ ep_sh = vls_to_sh (ep_vls);
sh = vls_to_sh (vls);
vls_epoll_ctl_mp_checks (vls, op);