aboutsummaryrefslogtreecommitdiffstats
path: root/src/vcl
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2018-12-14 11:28:43 -0800
committerDamjan Marion <dmarion@me.com>2018-12-17 08:47:39 +0000
commit3c7d4f9e1f54ec6627795b64525f182e2cda7490 (patch)
tree8d9ca4efe66a2f8f7cf56a3fe9c9d3b92561b26f /src/vcl
parent7bb27caf62f5fa942be68015aeb0543566d22371 (diff)
vcl/session: handle reset/disconnect before app accept
Also further improves reset handling. Change-Id: I6e517632f700f181761726b965134e0c217eb06d Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/vcl')
-rw-r--r--src/vcl/vcl_private.h11
-rw-r--r--src/vcl/vppcom.c202
2 files changed, 145 insertions, 68 deletions
diff --git a/src/vcl/vcl_private.h b/src/vcl/vcl_private.h
index 44c6520703e..3d6c85ea6f7 100644
--- a/src/vcl/vcl_private.h
+++ b/src/vcl/vcl_private.h
@@ -67,13 +67,13 @@ typedef enum
STATE_CONNECT = 0x02,
STATE_LISTEN = 0x04,
STATE_ACCEPT = 0x08,
- STATE_CLOSE_ON_EMPTY = 0x10,
+ STATE_VPP_CLOSING = 0x10,
STATE_DISCONNECT = 0x20,
STATE_FAILED = 0x40
} session_state_t;
-#define SERVER_STATE_OPEN (STATE_ACCEPT|STATE_CLOSE_ON_EMPTY)
-#define CLIENT_STATE_OPEN (STATE_CONNECT|STATE_CLOSE_ON_EMPTY)
+#define SERVER_STATE_OPEN (STATE_ACCEPT|STATE_VPP_CLOSING)
+#define CLIENT_STATE_OPEN (STATE_CONNECT|STATE_VPP_CLOSING)
#define STATE_OPEN (SERVER_STATE_OPEN | CLIENT_STATE_OPEN)
typedef struct epoll_event vppcom_epoll_event_t;
@@ -95,6 +95,9 @@ typedef struct
ip46_address_t ip46;
} vppcom_ip46_t;
+#define VCL_ACCEPTED_F_CLOSED (1 << 0)
+#define VCL_ACCEPTED_F_RESET (1 << 1)
+
typedef struct vcl_session_msg
{
u32 next;
@@ -102,6 +105,7 @@ typedef struct vcl_session_msg
{
session_accepted_msg_t accepted_msg;
};
+ u32 flags;
} vcl_session_msg_t;
enum
@@ -155,6 +159,7 @@ typedef struct
u32 sm_seg_index;
u32 client_context;
u64 vpp_handle;
+ u32 vpp_thread_index;
/* Socket configuration state */
u8 is_vep;
diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c
index 88a67ddab30..773350ae0c9 100644
--- a/src/vcl/vppcom.c
+++ b/src/vcl/vppcom.c
@@ -67,8 +67,8 @@ vppcom_session_state_str (session_state_t state)
st = "STATE_ACCEPT";
break;
- case STATE_CLOSE_ON_EMPTY:
- st = "STATE_CLOSE_ON_EMPTY";
+ case STATE_VPP_CLOSING:
+ st = "STATE_VPP_CLOSING";
break;
case STATE_DISCONNECT:
@@ -181,7 +181,7 @@ vcl_session_vpp_evt_q (vcl_worker_t * wrk, vcl_session_t * s)
if (vcl_session_is_ct (s))
return wrk->vpp_event_queues[0];
else
- return wrk->vpp_event_queues[s->tx_fifo->master_thread_index];
+ return wrk->vpp_event_queues[s->vpp_thread_index];
}
static void
@@ -289,6 +289,7 @@ vcl_session_accepted_handler (vcl_worker_t * wrk, session_accepted_msg_t * mp)
}
session->vpp_handle = mp->handle;
+ session->vpp_thread_index = rx_fifo->master_thread_index;
session->client_context = mp->context;
session->rx_fifo = rx_fifo;
session->tx_fifo = tx_fifo;
@@ -380,6 +381,7 @@ vcl_session_connected_handler (vcl_worker_t * wrk,
session->rx_fifo = rx_fifo;
session->tx_fifo = tx_fifo;
session->vpp_handle = mp->handle;
+ session->vpp_thread_index = rx_fifo->master_thread_index;
session->transport.is_ip4 = mp->is_ip4;
clib_memcpy_fast (&session->transport.lcl_ip, mp->lcl_ip,
sizeof (session->transport.lcl_ip));
@@ -387,7 +389,7 @@ vcl_session_connected_handler (vcl_worker_t * wrk,
session->session_state = STATE_CONNECT;
/* Add it to lookup table */
- hash_set (wrk->session_index_by_vpp_handles, mp->handle, session_index);
+ vcl_session_table_add_vpp_handle (wrk, mp->handle, session_index);
VDBG (1, "VCL<%d>: vpp handle 0x%llx, sid %u: connect succeeded! "
"session_rx_fifo %p, refcnt %d, session_tx_fifo %p, refcnt %d",
@@ -397,6 +399,24 @@ vcl_session_connected_handler (vcl_worker_t * wrk,
return session_index;
}
+static int
+vcl_flag_accepted_session (vcl_session_t * session, u64 handle, u32 flags)
+{
+ vcl_session_msg_t *accepted_msg;
+ int i;
+
+ for (i = 0; i < vec_len (session->accept_evts_fifo); i++)
+ {
+ accepted_msg = &session->accept_evts_fifo[i];
+ if (accepted_msg->accepted_msg.handle == handle)
+ {
+ accepted_msg->flags = flags;
+ return 1;
+ }
+ }
+ return 0;
+}
+
static u32
vcl_session_reset_handler (vcl_worker_t * wrk,
session_reset_msg_t * reset_msg)
@@ -411,8 +431,21 @@ vcl_session_reset_handler (vcl_worker_t * wrk,
VDBG (0, "request to reset unknown handle 0x%llx", reset_msg->handle);
return VCL_INVALID_SESSION_INDEX;
}
- session->session_state = STATE_CLOSE_ON_EMPTY;
- VDBG (0, "reset handle 0x%llx, sid %u ", reset_msg->handle, sid);
+ if (session->session_state >= STATE_VPP_CLOSING)
+ return sid;
+
+ /* Caught a reset before actually accepting the session */
+ if (session->session_state == STATE_LISTEN)
+ {
+
+ if (!vcl_flag_accepted_session (session, reset_msg->handle,
+ VCL_ACCEPTED_F_RESET))
+ VDBG (0, "session was not accepted!");
+ return VCL_INVALID_SESSION_INDEX;
+ }
+
+ session->session_state = STATE_DISCONNECT;
+ VDBG (0, "reset session %u [0x%llx]", sid, reset_msg->handle);
vcl_send_session_reset_reply (vcl_session_vpp_evt_q (wrk, session),
wrk->my_client_index, reset_msg->handle, 0);
return sid;
@@ -468,15 +501,64 @@ vcl_session_bound_handler (vcl_worker_t * wrk, session_bound_msg_t * mp)
return sid;
}
+static vcl_session_t *
+vcl_session_accepted (vcl_worker_t * wrk, session_accepted_msg_t * msg)
+{
+ vcl_session_msg_t *vcl_msg;
+ vcl_session_t *session;
+
+ session = vcl_session_get_w_vpp_handle (wrk, msg->handle);
+ if (PREDICT_FALSE (session != 0))
+ VWRN ("session handle overlap %lu!", msg->handle);
+
+ session = vcl_session_table_lookup_listener (wrk, msg->listener_handle);
+ if (!session)
+ {
+ VERR ("couldn't find listen session: listener handle %llx",
+ msg->listener_handle);
+ return 0;
+ }
+
+ clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
+ vcl_msg->accepted_msg = *msg;
+ /* Session handle points to listener until fully accepted by app */
+ vcl_session_table_add_vpp_handle (wrk, msg->handle, session->session_index);
+
+ return session;
+}
+
+static vcl_session_t *
+vcl_session_disconnected_handler (vcl_worker_t * wrk,
+ session_disconnected_msg_t * msg)
+{
+ vcl_session_t *session;
+
+ session = vcl_session_get_w_vpp_handle (wrk, msg->handle);
+ if (!session)
+ {
+ VDBG (0, "request to disconnect unknown handle 0x%llx", msg->handle);
+ return 0;
+ }
+
+ /* Caught a disconnect before actually accepting the session */
+ if (session->session_state == STATE_LISTEN)
+ {
+
+ if (!vcl_flag_accepted_session (session, msg->handle,
+ VCL_ACCEPTED_F_CLOSED))
+ VDBG (0, "session was not accepted!");
+ return 0;
+ }
+
+ session->session_state = STATE_VPP_CLOSING;
+ return session;
+}
+
static int
vcl_handle_mq_event (vcl_worker_t * wrk, session_event_t * e)
{
- session_accepted_msg_t *accepted_msg;
session_disconnected_msg_t *disconnected_msg;
- vcl_session_msg_t *vcl_msg;
vcl_session_t *session;
- u64 handle;
- u32 sid;
switch (e->event_type)
{
@@ -487,18 +569,7 @@ vcl_handle_mq_event (vcl_worker_t * wrk, session_event_t * e)
vec_add1 (wrk->unhandled_evts_vector, *e);
break;
case SESSION_CTRL_EVT_ACCEPTED:
- accepted_msg = (session_accepted_msg_t *) e->data;
- handle = accepted_msg->listener_handle;
- session = vcl_session_table_lookup_listener (wrk, handle);
- if (!session)
- {
- clib_warning ("VCL<%d>: ERROR: couldn't find listen session:"
- "listener handle %llx", getpid (), handle);
- break;
- }
-
- clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
- vcl_msg->accepted_msg = *accepted_msg;
+ vcl_session_accepted (wrk, (session_accepted_msg_t *) e->data);
break;
case SESSION_CTRL_EVT_CONNECTED:
vcl_session_connected_handler (wrk,
@@ -506,17 +577,12 @@ vcl_handle_mq_event (vcl_worker_t * wrk, session_event_t * e)
break;
case SESSION_CTRL_EVT_DISCONNECTED:
disconnected_msg = (session_disconnected_msg_t *) e->data;
- sid = vcl_session_index_from_vpp_handle (wrk, disconnected_msg->handle);
- session = vcl_session_get (wrk, sid);
+ session = vcl_session_disconnected_handler (wrk, disconnected_msg);
if (!session)
- {
- VDBG (0, "request to disconnect unknown handle 0x%llx",
- disconnected_msg->handle);
- break;
- }
+ break;
session->session_state = STATE_DISCONNECT;
- VDBG (0, "disconnected handle 0x%llx, sid %u", disconnected_msg->handle,
- sid);
+ VDBG (0, "disconnected session %u [0x%llx]", session->session_index,
+ session->vpp_handle);
break;
case SESSION_CTRL_EVT_RESET:
vcl_session_reset_handler (wrk, (session_reset_msg_t *) e->data);
@@ -663,7 +729,7 @@ vppcom_session_disconnect (u32 session_handle)
return VPPCOM_EBADFD;
}
- if (state & STATE_CLOSE_ON_EMPTY)
+ if (state & STATE_VPP_CLOSING)
{
vpp_evt_q = vcl_session_vpp_evt_q (wrk, session);
vcl_send_session_disconnected_reply (vpp_evt_q, wrk->my_client_index,
@@ -1202,7 +1268,7 @@ int
vppcom_session_accept (uint32_t listen_session_handle, vppcom_endpt_t * ep,
uint32_t flags)
{
- u32 client_session_index = ~0, listen_session_index;
+ u32 client_session_index = ~0, listen_session_index, accept_flags = 0;
vcl_worker_t *wrk = vcl_worker_get_current ();
session_accepted_msg_t accepted_msg;
vcl_session_t *listen_session = 0;
@@ -1226,6 +1292,7 @@ vppcom_session_accept (uint32_t listen_session_handle, vppcom_endpt_t * ep,
if (clib_fifo_elts (listen_session->accept_evts_fifo))
{
clib_fifo_sub2 (listen_session->accept_evts_fifo, evt);
+ accept_flags = evt->flags;
accepted_msg = evt->accepted_msg;
goto handle;
}
@@ -1302,6 +1369,25 @@ handle:
vcl_evt (VCL_EVT_ACCEPT, client_session, listen_session,
client_session_index);
+ /*
+ * Session might have been closed already
+ */
+ if (accept_flags)
+ {
+ svm_msg_q_t *mq = vcl_session_vpp_evt_q (wrk, client_session);
+ if (accept_flags & VCL_ACCEPTED_F_CLOSED)
+ {
+ client_session->session_state = STATE_DISCONNECT;
+ vcl_send_session_disconnected_reply (mq, wrk->my_client_index,
+ client_session->vpp_handle, 0);
+ }
+ else if (accept_flags & VCL_ACCEPTED_F_RESET)
+ {
+ client_session->session_state = STATE_DISCONNECT;
+ vcl_send_session_reset_reply (mq, wrk->my_client_index,
+ client_session->vpp_handle, 0);
+ }
+ }
return vcl_session_handle (client_session);
}
@@ -1472,7 +1558,7 @@ vppcom_session_read_internal (uint32_t session_handle, void *buf, int n,
}
svm_msg_q_free_msg (mq, &msg);
- if (PREDICT_FALSE (s->session_state == STATE_CLOSE_ON_EMPTY))
+ if (PREDICT_FALSE (s->session_state == STATE_VPP_CLOSING))
return 0;
}
}
@@ -1565,7 +1651,7 @@ vppcom_session_read_segments (uint32_t session_handle,
}
svm_msg_q_free_msg (mq, &msg);
- if (PREDICT_FALSE (s->session_state == STATE_CLOSE_ON_EMPTY))
+ if (PREDICT_FALSE (s->session_state == STATE_VPP_CLOSING))
return 0;
}
}
@@ -1719,6 +1805,9 @@ vppcom_session_write_inline (uint32_t session_handle, void *buf, size_t n,
}
}
+ if (PREDICT_FALSE (!(s->session_state & STATE_OPEN)))
+ return VPPCOM_ECONNRESET;
+
ASSERT (FIFO_EVENT_APP_TX + 1 == SESSION_IO_EVT_CT_TX);
et = FIFO_EVENT_APP_TX + vcl_session_is_ct (s);
if (is_flush && !vcl_session_is_ct (s))
@@ -1845,10 +1934,7 @@ vcl_select_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
{
session_disconnected_msg_t *disconnected_msg;
session_connected_msg_t *connected_msg;
- session_accepted_msg_t *accepted_msg;
- vcl_session_msg_t *vcl_msg;
vcl_session_t *session;
- u64 handle;
u32 sid;
switch (e->event_type)
@@ -1900,18 +1986,10 @@ vcl_select_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
}
break;
case SESSION_CTRL_EVT_ACCEPTED:
- accepted_msg = (session_accepted_msg_t *) e->data;
- handle = accepted_msg->listener_handle;
- session = vcl_session_table_lookup_listener (wrk, handle);
+ session = vcl_session_accepted (wrk,
+ (session_accepted_msg_t *) e->data);
if (!session)
- {
- clib_warning ("VCL<%d>: ERROR: couldn't find listen session:"
- "listener handle %llx", getpid (), handle);
- break;
- }
-
- clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
- vcl_msg->accepted_msg = *accepted_msg;
+ break;
sid = session->session_index;
if (sid < n_bits && read_map)
{
@@ -1925,7 +2003,10 @@ vcl_select_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
break;
case SESSION_CTRL_EVT_DISCONNECTED:
disconnected_msg = (session_disconnected_msg_t *) e->data;
- sid = vcl_session_index_from_vpp_handle (wrk, disconnected_msg->handle);
+ session = vcl_session_disconnected_handler (wrk, disconnected_msg);
+ if (!session)
+ break;
+ sid = session->session_index;
if (sid < n_bits && except_map)
{
clib_bitmap_set_no_check (except_map, sid, 1);
@@ -2454,10 +2535,8 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
{
session_disconnected_msg_t *disconnected_msg;
session_connected_msg_t *connected_msg;
- session_accepted_msg_t *accepted_msg;
- u64 session_evt_data = ~0, handle;
u32 sid = ~0, session_events;
- vcl_session_msg_t *vcl_msg;
+ u64 session_evt_data = ~0;
vcl_session_t *session;
u8 add_event = 0;
@@ -2509,18 +2588,11 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
session_evt_data = session->vep.ev.data.u64;
break;
case SESSION_CTRL_EVT_ACCEPTED:
- accepted_msg = (session_accepted_msg_t *) e->data;
- handle = accepted_msg->listener_handle;
- session = vcl_session_table_lookup_listener (wrk, handle);
+ session = vcl_session_accepted (wrk,
+ (session_accepted_msg_t *) e->data);
if (!session)
- {
- clib_warning ("VCL<%d>: ERROR: couldn't find listen session:"
- "listener handle %llx", getpid (), handle);
- break;
- }
+ break;
- clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
- vcl_msg->accepted_msg = *accepted_msg;
session_events = session->vep.ev.events;
if (!(EPOLLIN & session_events))
break;
@@ -2545,8 +2617,8 @@ vcl_epoll_wait_handle_mq_event (vcl_worker_t * wrk, session_event_t * e,
break;
case SESSION_CTRL_EVT_DISCONNECTED:
disconnected_msg = (session_disconnected_msg_t *) e->data;
- sid = vcl_session_index_from_vpp_handle (wrk, disconnected_msg->handle);
- if (!(session = vcl_session_get (wrk, sid)))
+ session = vcl_session_disconnected_handler (wrk, disconnected_msg);
+ if (!session)
break;
add_event = 1;
events[*num_ev].events |= EPOLLHUP | EPOLLRDHUP;