- transport_endpoint_t *tep;
- clib_spinlock_lock_if_init (&local_endpoints_lock);
- tep = transport_endpoint_new ();
- clib_memcpy_fast (&tep->ip, ip, sizeof (*ip));
- tep->port = port;
- transport_endpoint_table_add (&local_endpoints_table, proto, tep,
- tep - local_endpoints);
- clib_spinlock_unlock_if_init (&local_endpoints_lock);
+ transport_main_t *tm = &tp_main;
+ local_endpoint_t *lep;
+ u32 tei;
+
+ ASSERT (vlib_get_thread_index () <= transport_cl_thread ());
+
+ tei =
+ transport_endpoint_lookup (&tm->local_endpoints_table, proto, ip, port);
+ if (tei != ENDPOINT_INVALID_INDEX)
+ return SESSION_E_PORTINUSE;
+
+ /* Pool reallocs with worker barrier */
+ lep = transport_endpoint_alloc ();
+ clib_memcpy_fast (&lep->ep.ip, ip, sizeof (*ip));
+ lep->ep.port = port;
+ lep->proto = proto;
+ lep->refcnt = 1;
+
+ transport_endpoint_table_add (&tm->local_endpoints_table, proto, &lep->ep,
+ lep - tm->local_endpoints);
+
+ return 0;
+}
+
+void
+transport_share_local_endpoint (u8 proto, ip46_address_t * lcl_ip, u16 port)
+{
+ transport_main_t *tm = &tp_main;
+ local_endpoint_t *lep;
+ u32 lepi;
+
+ /* Active opens should call this only from a control thread, which are also
+ * used to allocate and free ports. So, pool has only one writer and
+ * potentially many readers. Listeners are allocated with barrier */
+ lepi = transport_endpoint_lookup (&tm->local_endpoints_table, proto, lcl_ip,
+ clib_net_to_host_u16 (port));
+ if (lepi != ENDPOINT_INVALID_INDEX)
+ {
+ lep = pool_elt_at_index (tm->local_endpoints, lepi);
+ clib_atomic_add_fetch (&lep->refcnt, 1);
+ }