aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAloys Augustin <aloaugus@cisco.com>2019-08-06 16:09:01 +0200
committerFlorin Coras <florin.coras@gmail.com>2019-08-08 02:25:24 +0000
commit7119c22f82312e92cb4d0c43ac0196961532b230 (patch)
treea463e9faf72a75cfaa073827b88b44fae29eba1a
parent23526f78a8bd5507624a72476550fc604de3a22a (diff)
udp: fix connections move
Without this the use of uc0 is racy between the current thread and the thread that owns it and will delete it. This also ensures we don't trigger a read event on the session before moving it to the right thread and notifying the application. Type: fix Change-Id: Icb1ca3ee5805ea3c0d2d424d4b23511465deb3b6 Signed-off-by: Aloys Augustin <aloaugus@cisco.com> (cherry picked from commit b3392334942ed5459edfa7f11e098f4eab3aa29a)
-rw-r--r--src/vnet/session/session.c28
-rw-r--r--src/vnet/udp/udp_input.c5
2 files changed, 32 insertions, 1 deletions
diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c
index 3d22cc27ef4..33f1e26fd6d 100644
--- a/src/vnet/session/session.c
+++ b/src/vnet/session/session.c
@@ -565,6 +565,31 @@ session_enqueue_notify (session_t * s)
return session_enqueue_notify_inline (s);
}
+static void
+session_enqueue_notify_rpc (void *arg)
+{
+ session_handle_t sh = (session_handle_t) arg;
+ session_t *s;
+
+ s = session_get_from_handle_if_valid (sh);
+ if (!s)
+ return;
+
+ session_enqueue_notify (s);
+}
+
+/**
+ * Like session_enqueue_notify, but can be called from a thread that does not
+ * own the session.
+ */
+void
+session_enqueue_notify_thread (session_handle_t sh)
+{
+ u32 thread_index = session_thread_from_handle (sh);
+ session_send_rpc_evt_to_thread (thread_index,
+ session_enqueue_notify_rpc, (void *) sh);
+}
+
int
session_dequeue_notify (session_t * s)
{
@@ -739,6 +764,9 @@ session_switch_pool (void *cb_args)
new_sh = session_make_handle (args->new_session_index,
args->new_thread_index);
app_worker_migrate_notify (app_wrk, s, new_sh);
+
+ /* Trigger app read on the new thread */
+ session_enqueue_notify_thread (new_sh);
}
session_free (s);
diff --git a/src/vnet/udp/udp_input.c b/src/vnet/udp/udp_input.c
index 936d94d69ce..ad86f439fd7 100644
--- a/src/vnet/udp/udp_input.c
+++ b/src/vnet/udp/udp_input.c
@@ -110,6 +110,7 @@ udp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
int wrote0;
void *rmt_addr, *lcl_addr;
session_dgram_hdr_t hdr0;
+ u8 queue_event = 1;
/* speculatively enqueue b0 to the current next frame */
bi0 = from[0];
@@ -182,6 +183,8 @@ udp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
session_dgram_connect_notify (&new_uc0->connection,
s0->thread_index, &s0);
tc0 = &new_uc0->connection;
+ uc0 = new_uc0;
+ queue_event = 0;
}
else
s0->session_state = SESSION_STATE_READY;
@@ -254,7 +257,7 @@ udp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
clib_spinlock_lock (&uc0->rx_lock);
wrote0 = session_enqueue_dgram_connection (s0, &hdr0, b0,
TRANSPORT_PROTO_UDP,
- 1 /* queue evt */ );
+ queue_event);
clib_spinlock_unlock (&uc0->rx_lock);
ASSERT (wrote0 > 0);