+ return
+ pool_elt_at_index (smm->sessions[session_thread_from_handle (handle)],
+ session_index_from_handle (handle));
+}
+
+always_inline transport_proto_t
+session_get_transport_proto (stream_session_t * s)
+{
+ return (s->session_type >> 1);
+}
+
+always_inline session_type_t
+session_type_from_proto_and_ip (transport_proto_t proto, u8 is_ip4)
+{
+ return (proto << 1 | is_ip4);
+}
+
+/**
+ * Acquires a lock that blocks a session pool from expanding.
+ *
+ * This is typically used for safely peeking into other threads'
+ * pools in order to clone elements. Lock should be dropped as soon
+ * as possible by calling @ref session_pool_remove_peeker.
+ *
+ * NOTE: Avoid using pool_elt_at_index while the lock is held because
+ * it may lead to free elt bitmap expansion/contraction!
+ */
+always_inline void
+session_pool_add_peeker (u32 thread_index)
+{
+ session_manager_main_t *smm = &session_manager_main;
+ if (thread_index == vlib_get_thread_index ())
+ return;
+ clib_rwlock_reader_lock (&smm->peekers_rw_locks[thread_index]);
+}
+
+always_inline void
+session_pool_remove_peeker (u32 thread_index)
+{
+ session_manager_main_t *smm = &session_manager_main;
+ if (thread_index == vlib_get_thread_index ())
+ return;
+ clib_rwlock_reader_unlock (&smm->peekers_rw_locks[thread_index]);
+}
+
+/**
+ * Get session from handle and 'lock' pool resize if not in same thread
+ *
+ * Caller should drop the peek 'lock' as soon as possible.
+ */
+always_inline stream_session_t *
+session_get_from_handle_safe (u64 handle)
+{
+ session_manager_main_t *smm = &session_manager_main;
+ u32 thread_index = session_thread_from_handle (handle);
+ if (thread_index == vlib_get_thread_index ())
+ {
+ return pool_elt_at_index (smm->sessions[thread_index],
+ session_index_from_handle (handle));
+ }
+ else
+ {
+ session_pool_add_peeker (thread_index);
+ /* Don't use pool_elt_at index. See @ref session_pool_add_peeker */
+ return smm->sessions[thread_index] + session_index_from_handle (handle);
+ }