#include <vnet/session/session.h>
#include <vnet/fib/fib.h>
+typedef struct local_endpoint_
+{
+ transport_endpoint_t ep;
+ int refcnt;
+} local_endpoint_t;
+
/**
* Per-type vector of transport protocol virtual function tables
*/
/*
* Pool of local endpoints
*/
-static transport_endpoint_t *local_endpoints;
+static local_endpoint_t *local_endpoints;
/*
* Local endpoints pool lock
clib_spinlock_unlock_if_init (&local_endpoints_lock);
}
-always_inline transport_endpoint_t *
+always_inline local_endpoint_t *
transport_endpoint_new (void)
{
- transport_endpoint_t *tep;
- pool_get_zero (local_endpoints, tep);
- return tep;
+ local_endpoint_t *lep;
+ pool_get_zero (local_endpoints, lep);
+ return lep;
}
void
transport_endpoint_cleanup (u8 proto, ip46_address_t * lcl_ip, u16 port)
{
- u32 tepi;
- transport_endpoint_t *tep;
+ local_endpoint_t *lep;
+ u32 lepi;
/* Cleanup local endpoint if this was an active connect */
- tepi = transport_endpoint_lookup (&local_endpoints_table, proto, lcl_ip,
+ lepi = transport_endpoint_lookup (&local_endpoints_table, proto, lcl_ip,
clib_net_to_host_u16 (port));
- if (tepi != ENDPOINT_INVALID_INDEX)
+ if (lepi != ENDPOINT_INVALID_INDEX)
{
- tep = pool_elt_at_index (local_endpoints, tepi);
- transport_endpoint_table_del (&local_endpoints_table, proto, tep);
- transport_endpoint_del (tepi);
+ lep = pool_elt_at_index (local_endpoints, lepi);
+ if (!clib_atomic_sub_fetch (&lep->refcnt, 1))
+ {
+ transport_endpoint_table_del (&local_endpoints_table, proto,
+ &lep->ep);
+ transport_endpoint_del (lepi);
+ }
}
}
static void
transport_endpoint_mark_used (u8 proto, ip46_address_t * ip, u16 port)
{
- transport_endpoint_t *tep;
+ local_endpoint_t *lep;
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);
+ lep = transport_endpoint_new ();
+ clib_memcpy_fast (&lep->ep.ip, ip, sizeof (*ip));
+ lep->ep.port = port;
+ lep->refcnt = 1;
+ transport_endpoint_table_add (&local_endpoints_table, proto, &lep->ep,
+ lep - local_endpoints);
clib_spinlock_unlock_if_init (&local_endpoints_lock);
}
+void
+transport_share_local_endpoint (u8 proto, ip46_address_t * lcl_ip, u16 port)
+{
+ local_endpoint_t *lep;
+ u32 lepi;
+
+ lepi = transport_endpoint_lookup (&local_endpoints_table, proto, lcl_ip,
+ clib_net_to_host_u16 (port));
+ if (lepi != ENDPOINT_INVALID_INDEX)
+ {
+ lep = pool_elt_at_index (local_endpoints, lepi);
+ clib_atomic_add_fetch (&lep->refcnt, 1);
+ }
+}
+
/**
* Allocate local port and add if successful add entry to local endpoint
* table to mark the pair as used.
return -1;
}
-static clib_error_t *
+static session_error_t
transport_get_interface_ip (u32 sw_if_index, u8 is_ip4, ip46_address_t * addr)
{
if (is_ip4)
ip4_address_t *ip4;
ip4 = ip_interface_get_first_ip (sw_if_index, 1);
if (!ip4)
- return clib_error_return (0, "no routable ip4 address on %U",
- format_vnet_sw_if_index_name,
- vnet_get_main (), sw_if_index);
+ return SESSION_E_NOIP;
addr->ip4.as_u32 = ip4->as_u32;
}
else
ip6_address_t *ip6;
ip6 = ip_interface_get_first_ip (sw_if_index, 0);
if (ip6 == 0)
- return clib_error_return (0, "no routable ip6 addresses on %U",
- format_vnet_sw_if_index_name,
- vnet_get_main (), sw_if_index);
+ return SESSION_E_NOIP;
clib_memcpy_fast (&addr->ip6, ip6, sizeof (*ip6));
}
return 0;
}
-static clib_error_t *
+static session_error_t
transport_find_local_ip_for_remote (u32 sw_if_index,
transport_endpoint_t * rmt,
ip46_address_t * lcl_addr)
/* Couldn't find route to destination. Bail out. */
if (fei == FIB_NODE_INDEX_INVALID)
- return clib_error_return (0, "no route to %U", format_ip46_address,
- &rmt->ip, (rmt->is_ip4 == 0) + 1);
+ return SESSION_E_NOROUTE;
sw_if_index = fib_entry_get_resolving_interface (fei);
if (sw_if_index == ENDPOINT_INVALID_INDEX)
- return clib_error_return (0, "no resolving interface for %U",
- format_ip46_address, &rmt->ip,
- (rmt->is_ip4 == 0) + 1);
+ return SESSION_E_NOINTF;
}
clib_memset (lcl_addr, 0, sizeof (*lcl_addr));
ip46_address_t * lcl_addr, u16 * lcl_port)
{
transport_endpoint_t *rmt = (transport_endpoint_t *) rmt_cfg;
- clib_error_t *error;
+ session_error_t error;
int port;
u32 tei;
error = transport_find_local_ip_for_remote (rmt_cfg->peer.sw_if_index,
rmt, lcl_addr);
if (error)
- {
- clib_error_report (error);
- return -1;
- }
+ return error;
}
else
{
{
port = transport_alloc_local_port (proto, lcl_addr);
if (port < 1)
- {
- clib_warning ("Failed to allocate src port");
- return -1;
- }
+ return SESSION_E_NOPORT;
*lcl_port = port;
}
else
{
port = clib_net_to_host_u16 (rmt_cfg->peer.port);
+ *lcl_port = port;
tei = transport_endpoint_lookup (&local_endpoints_table, proto,
lcl_addr, port);
if (tei != ENDPOINT_INVALID_INDEX)
- return -1;
+ return SESSION_E_PORTINUSE;
transport_endpoint_mark_used (proto, lcl_addr, port);
- *lcl_port = port;
}
return 0;