|
|
|
|
@ -19,6 +19,7 @@
|
|
|
|
|
#include "route_connectivity.h" |
|
|
|
|
#include "topo_node_sqlite.h" |
|
|
|
|
#include "sock_match.h" |
|
|
|
|
#include "nat_detection.h" |
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
|
#include "standby.h" |
|
|
|
|
#endif |
|
|
|
|
@ -253,6 +254,24 @@ static void conn_probe_finish(struct conn_probe_ctx* ctx, int ok) {
|
|
|
|
|
|
|
|
|
|
// ---- public API ----
|
|
|
|
|
|
|
|
|
|
struct route_nat_defer { |
|
|
|
|
struct UTUN_INSTANCE *instance; |
|
|
|
|
struct TOPO_GROUP *group; |
|
|
|
|
struct TOPO_GROUP_NODE *node; |
|
|
|
|
void *timer; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/* После NAT-окна запускает обычную проверку; удаление узла отменяет таймер и освобождает контекст. */ |
|
|
|
|
static void route_nat_deferred_cb(void *arg) { |
|
|
|
|
struct route_nat_defer *deferred = arg; |
|
|
|
|
struct UTUN_INSTANCE *instance = deferred->instance; |
|
|
|
|
struct TOPO_GROUP *group = deferred->group; |
|
|
|
|
struct TOPO_GROUP_NODE *node = deferred->node; |
|
|
|
|
node->connectivity.nat_probe_wait = NULL; node->connectivity.probe_status = PROBE_STATUS_NONE; |
|
|
|
|
u_free(deferred); |
|
|
|
|
route_connectivity_probe_node(instance, group, node); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
|
/* Контекст пробы, отложенной до следующего активного интервала (standby_wait). */ |
|
|
|
|
struct route_probe_defer { |
|
|
|
|
@ -277,6 +296,7 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_G
|
|
|
|
|
struct TOPO_NODE* ni = topo_node_registry_find(instance->topo_groups, nq->node_id); |
|
|
|
|
if (!ni) return; |
|
|
|
|
if (nq->node_id == instance->node_id) return; // не пингуем себя
|
|
|
|
|
if (nq->connectivity.nat_probe_wait) return; |
|
|
|
|
/* Пир в SLEEP-фазе: прямое соединение живо, probe будит пира — пропускаем. */ |
|
|
|
|
{ |
|
|
|
|
struct ETCP_CONN* c = instance_find_conn(instance, nq->node_id); |
|
|
|
|
@ -303,6 +323,19 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_G
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint64_t nat_delay = nat_detection_probe_delay(instance->nat_det); |
|
|
|
|
if (nat_delay) { |
|
|
|
|
struct route_nat_defer *deferred = u_calloc(1, sizeof(*deferred)); |
|
|
|
|
if (!deferred) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NAT probe defer allocation failed"); return; } |
|
|
|
|
deferred->instance = instance; deferred->group = group; deferred->node = nq; |
|
|
|
|
deferred->timer = uasync_set_timeout(instance->ua, nat_delay, deferred, route_nat_deferred_cb, "route_nat_defer"); |
|
|
|
|
if (!deferred->timer) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NAT probe defer scheduling failed"); u_free(deferred); return; } |
|
|
|
|
nq->connectivity.nat_probe_wait = deferred; nq->connectivity.probe_status = PROBE_STATUS_DEFERRED; |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "connectivity probe waits for initial NAT measurement node=%016llx delay_tb=%llu", |
|
|
|
|
(unsigned long long)nq->node_id, (unsigned long long)nat_delay); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nq->connectivity.probe_status = PROBE_STATUS_IN_PROGRESS; |
|
|
|
|
nq->connectivity.probe_start_time = get_time_tb(); |
|
|
|
|
nq->connectivity.interface_status = PROBE_RESULT_UNKNOWN; |
|
|
|
|
@ -422,6 +455,11 @@ void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_G
|
|
|
|
|
* хендла — они отсоединяются и освобождаются своим штатным ping_timeout/PONG. */ |
|
|
|
|
static void conn_probe_cancel_nq(struct TOPO_GROUP_NODE* nq) { |
|
|
|
|
if (!nq) return; |
|
|
|
|
struct route_nat_defer *deferred = nq->connectivity.nat_probe_wait; |
|
|
|
|
if (deferred) { |
|
|
|
|
uasync_cancel_timeout(deferred->instance->ua, deferred->timer); |
|
|
|
|
nq->connectivity.nat_probe_wait = NULL; u_free(deferred); |
|
|
|
|
} |
|
|
|
|
#ifdef UTUN_HAVE_STANDBY |
|
|
|
|
{ struct route_probe_defer* d = (struct route_probe_defer*)nq->connectivity.probe_deferred_wait; |
|
|
|
|
if (d) { |
|
|
|
|
|