if (ls->flags & VCL_SESSION_F_PENDING_LISTEN)
return;
+ ls->flags &= ~VCL_SESSION_F_LISTEN_NO_MQ;
vcl_send_session_listen (wrk, ls);
vls_listener_wrk_set (vls, wrk_index, 1 /* is_active */);
if (s->session_state != VCL_STATE_LISTEN)
return;
vcl_send_session_unlisten (wrk, s);
- s->session_state = VCL_STATE_LISTEN_NO_MQ;
+ s->flags |= VCL_SESSION_F_LISTEN_NO_MQ;
vls_listener_wrk_set (vls, wrk_index, 0 /* is_active */ );
}
if (s->session_state == VCL_STATE_LISTEN)
{
- s->session_state = VCL_STATE_LISTEN_NO_MQ;
+ s->flags |= VCL_SESSION_F_LISTEN_NO_MQ;
s->rx_fifo = s->tx_fifo = 0;
}
else if (s->rx_fifo)
switch (s->session_state)
{
case VCL_STATE_LISTEN:
- if (is_add)
+ if (!(s->flags & VCL_SESSION_F_LISTEN_NO_MQ))
{
- vls_listener_wrk_set (vls, vls->vcl_wrk_index, 1 /* is_active */);
- break;
+ if (is_add)
+ {
+ vls_listener_wrk_set (vls, vls->vcl_wrk_index,
+ 1 /* is_active */);
+ break;
+ }
+ /* 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); */
+ }
+ else
+ {
+ if (!is_add)
+ break;
+
+ /* Register worker as listener */
+ vls_listener_wrk_start_listen (vls, vls->vcl_wrk_index);
+
+ /* If owner worker did not attempt to accept/xpoll on the session,
+ * force a listen stop for it, since it may not be interested in
+ * accepting new sessions.
+ * This is pretty much a hack done to give app workers the illusion
+ * that it is fine to listen and not accept new sessions for a
+ * given listener. Without it, we would accumulate unhandled
+ * accepts on the passive worker message queue. */
+ owner_wrk = vls_shared_get_owner (vls);
+ if (!vls_listener_wrk_is_active (vls, owner_wrk))
+ vls_listener_wrk_stop_listen (vls, owner_wrk);
}
- /* 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)
- break;
-
- /* Register worker as listener */
- vls_listener_wrk_start_listen (vls, vls->vcl_wrk_index);
-
- /* If owner worker did not attempt to accept/xpoll on the session,
- * force a listen stop for it, since it may not be interested in
- * accepting new sessions.
- * This is pretty much a hack done to give app workers the illusion
- * that it is fine to listen and not accept new sessions for a
- * given listener. Without it, we would accumulate unhandled
- * accepts on the passive worker message queue. */
- owner_wrk = vls_shared_get_owner (vls);
- if (!vls_listener_wrk_is_active (vls, owner_wrk))
- vls_listener_wrk_stop_listen (vls, owner_wrk);
break;
default:
break;
{
if (s->session_state == VCL_STATE_LISTEN)
{
- s->session_state = VCL_STATE_LISTEN_NO_MQ;
+ s->flags |= VCL_SESSION_F_LISTEN_NO_MQ;
continue;
}
if ((s->flags & VCL_SESSION_F_IS_VEP) ||
- s->session_state == VCL_STATE_LISTEN_NO_MQ ||
s->session_state == VCL_STATE_CLOSED)
continue;
case VCL_STATE_UPDATED:
st = "STATE_UPDATED";
break;
- case VCL_STATE_LISTEN_NO_MQ:
- st = "STATE_LISTEN_NO_MQ";
- break;
default:
st = "UNKNOWN_STATE";
break;
VCL_STATE_DISCONNECT,
VCL_STATE_DETACHED,
VCL_STATE_UPDATED,
- VCL_STATE_LISTEN_NO_MQ,
} vcl_session_state_t;
typedef struct epoll_event vppcom_epoll_event_t;
VCL_SESSION_F_PENDING_FREE = 1 << 7,
VCL_SESSION_F_PENDING_LISTEN = 1 << 8,
VCL_SESSION_F_APP_CLOSING = 1 << 9,
+ VCL_SESSION_F_LISTEN_NO_MQ = 1 << 10,
} __clib_packed vcl_session_flags_t;
typedef enum vcl_worker_wait_
return 0;
}
- ASSERT (s->session_state == VCL_STATE_LISTEN
- || s->session_state == VCL_STATE_LISTEN_NO_MQ
- || vcl_session_is_connectable_listener (wrk, s));
+ ASSERT (s->session_state == VCL_STATE_LISTEN ||
+ vcl_session_is_connectable_listener (wrk, s));
return s;
}
}
/* Caught a reset before actually accepting the session */
- if (session->session_state == VCL_STATE_LISTEN ||
- session->session_state == VCL_STATE_LISTEN_NO_MQ)
+ if (session->session_state == VCL_STATE_LISTEN)
{
if (!vcl_flag_accepted_session (session, reset_msg->handle,
VCL_ACCEPTED_F_RESET))
return 0;
/* Caught a disconnect before actually accepting the session */
- if (session->session_state == VCL_STATE_LISTEN ||
- session->session_state == VCL_STATE_LISTEN_NO_MQ)
+ if (session->session_state == VCL_STATE_LISTEN)
{
if (!vcl_flag_accepted_session (session, msg->handle,
VCL_ACCEPTED_F_CLOSED))
* VPP_CLOSING state instead can been marked as ACCEPTED_F_CLOSED.
*/
if (vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK) &&
- !(s->session_state == VCL_STATE_LISTEN ||
- s->session_state == VCL_STATE_LISTEN_NO_MQ))
+ !(s->session_state == VCL_STATE_LISTEN))
{
s->session_state = VCL_STATE_VPP_CLOSING;
s->flags |= VCL_SESSION_F_PENDING_DISCONNECT;
* DISCONNECT state instead can been marked as ACCEPTED_F_RESET.
*/
if (vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK) &&
- !(s->session_state == VCL_STATE_LISTEN ||
- s->session_state == VCL_STATE_LISTEN_NO_MQ))
+ !(s->session_state == VCL_STATE_LISTEN))
{
s->flags |= VCL_SESSION_F_PENDING_DISCONNECT;
s->session_state = VCL_STATE_DISCONNECT;
}
clib_fifo_free (session->accept_evts_fifo);
+ if (session->flags & VCL_SESSION_F_LISTEN_NO_MQ)
+ {
+ vcl_session_free (wrk, session);
+ return VPPCOM_OK;
+ }
+
vcl_send_session_unlisten (wrk, session);
VDBG (0, "session %u [0x%llx]: sending unbind!", session->session_index,
{
if (s->flags & VCL_SESSION_F_IS_VEP)
continue;
- if (s->session_state == VCL_STATE_LISTEN_NO_MQ)
+ if (s->session_state == VCL_STATE_LISTEN)
vppcom_session_listen (vcl_session_handle (s), 10);
else
VDBG (0, "internal error: unexpected state %d", s->session_state);
return VPPCOM_EBADFD;
listen_vpp_handle = listen_session->vpp_handle;
- if (listen_session->session_state == VCL_STATE_LISTEN)
+ if (listen_session->session_state == VCL_STATE_LISTEN &&
+ !(listen_session->flags & VCL_SESSION_F_LISTEN_NO_MQ))
{
VDBG (0, "session %u [0x%llx]: already in listen state!",
listen_sh, listen_vpp_handle);
return VPPCOM_OK;
}
+ listen_session->flags &= ~VCL_SESSION_F_LISTEN_NO_MQ;
+
VDBG (0, "session %u: sending vpp listen request...", listen_sh);
/*
return VPPCOM_EBADFD;
if ((ls->session_state != VCL_STATE_LISTEN) &&
- (ls->session_state != VCL_STATE_LISTEN_NO_MQ) &&
(!vcl_session_is_connectable_listener (wrk, ls)))
{
VDBG (0, "ERROR: session [0x%llx]: not in listen state! state (%s)",