|
|
|
|
@ -1,7 +1,7 @@
|
|
|
|
|
// etcp_router.c — Сервисный слой маршрутизации поверх ETCP
|
|
|
|
|
// Упрощённый TCP: восстановление порядка (recv_q), дедупликация, без переповторов
|
|
|
|
|
// ACK: периодическая отправка rx_seq (не чаще 100ms), idle-таймер для последнего seq
|
|
|
|
|
// Inflight контроль: tx_seq - rx_acked < ROUTER_MAX_INFLIGHT
|
|
|
|
|
// Inflight контроль через send_q: при переполнении — очередь + retry-таймер, без дропов
|
|
|
|
|
#include "etcp_router.h" |
|
|
|
|
#include "etcp.h" |
|
|
|
|
#include "utun_instance.h" |
|
|
|
|
@ -19,9 +19,11 @@ static void router_ack_timer_cb(void* arg);
|
|
|
|
|
static void router_idle_ack_timer_cb(void* arg); |
|
|
|
|
static void router_send_ack(struct ETCP_ROUTER_CONN* rconn); |
|
|
|
|
static void router_schedule_ack(struct ETCP_ROUTER_CONN* rconn); |
|
|
|
|
static void router_try_assembly(struct ETCP_ROUTER_CONN* rconn); |
|
|
|
|
static void router_deliver(struct ETCP_ROUTER_CONN* rconn, |
|
|
|
|
const uint8_t* payload, size_t payload_len); |
|
|
|
|
static void router_try_assembly(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn); |
|
|
|
|
static void router_deliver(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, const uint8_t* payload, size_t payload_len); |
|
|
|
|
static int router_send_one(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len); |
|
|
|
|
static void router_drain_send_q(struct ETCP_ROUTER_CONN* rconn); |
|
|
|
|
static void router_send_resume_cb(void* arg); |
|
|
|
|
|
|
|
|
|
// ====================================================================
|
|
|
|
|
// Управление ROUTER_CONN
|
|
|
|
|
@ -36,6 +38,81 @@ static struct ETCP_ROUTER_CONN* router_conn_find(struct UTUN_INSTANCE* inst,
|
|
|
|
|
return (struct ETCP_ROUTER_CONN*)queue_find_data_by_index(inst->router_conns, key); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ====================================================================
|
|
|
|
|
// Отправка: router_send_one + send_q
|
|
|
|
|
// ====================================================================
|
|
|
|
|
|
|
|
|
|
static int router_send_one(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len) { |
|
|
|
|
struct UTUN_INSTANCE* inst = rconn->inst; |
|
|
|
|
uint32_t seq = rconn->tx_seq++; |
|
|
|
|
size_t total_len = SVC_ROUTE_HDR_SIZE + pl_len; |
|
|
|
|
uint8_t* dgram = u_malloc(total_len); |
|
|
|
|
if (!dgram) { rconn->tx_seq--; return -1; } |
|
|
|
|
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)dgram; |
|
|
|
|
hdr->cmd = ETCP_ID_SVC_ROUTE; |
|
|
|
|
hdr->dst_node_id = rconn->remote_node_id; |
|
|
|
|
hdr->src_node_id = inst->node_id; |
|
|
|
|
hdr->seq = seq; |
|
|
|
|
hdr->svc_id = rconn->svc_id; |
|
|
|
|
if (pl_len > 0) memcpy(dgram + SVC_ROUTE_HDR_SIZE, payload, pl_len); |
|
|
|
|
|
|
|
|
|
struct ll_entry* entry = queue_entry_new(0); |
|
|
|
|
if (!entry) { u_free(dgram); rconn->tx_seq--; return -1; } |
|
|
|
|
entry->dgram = dgram; |
|
|
|
|
entry->len = total_len; |
|
|
|
|
|
|
|
|
|
struct ETCP_CONN* conn = route_bgp_find_conn_for_node(inst->bgp, rconn->remote_node_id); |
|
|
|
|
if (!conn) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "router_send_one: no route to %016llx svc_id=%u", |
|
|
|
|
(unsigned long long)rconn->remote_node_id, rconn->svc_id); |
|
|
|
|
queue_entry_free(entry); queue_dgram_free(entry); rconn->tx_seq--; return -1; |
|
|
|
|
} |
|
|
|
|
rconn->last_dgram_ts = get_current_timestamp(); |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "router_send: seq=%u → %016llx svc_id=%u len=%zu inflight=%u", |
|
|
|
|
seq, (unsigned long long)rconn->remote_node_id, rconn->svc_id, pl_len, |
|
|
|
|
rconn->tx_seq - rconn->rx_acked); |
|
|
|
|
return etcp_send(conn, entry); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void router_drain_send_q(struct ETCP_ROUTER_CONN* rconn) { |
|
|
|
|
while (1) { |
|
|
|
|
if (rconn->tx_seq - rconn->rx_acked >= ROUTER_MAX_INFLIGHT) break; |
|
|
|
|
struct ll_entry* e = queue_data_get(rconn->send_q); |
|
|
|
|
if (!e) { rconn->send_blocked = 0; break; } |
|
|
|
|
router_send_one(rconn, e->dgram, e->len); |
|
|
|
|
queue_dgram_free(e); queue_entry_free(e); |
|
|
|
|
} |
|
|
|
|
if (rconn->send_blocked && !rconn->send_resume_timer) |
|
|
|
|
rconn->send_resume_timer = uasync_set_timeout(rconn->inst->ua, |
|
|
|
|
ROUTER_SEND_RESUME_TB, rconn, router_send_resume_cb, "router_send_resume"); |
|
|
|
|
if (!rconn->send_blocked && rconn->send_resume_timer) { |
|
|
|
|
uasync_cancel_timeout(rconn->inst->ua, rconn->send_resume_timer); |
|
|
|
|
rconn->send_resume_timer = NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void router_send_resume_cb(void* arg) { |
|
|
|
|
struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)arg; |
|
|
|
|
rconn->send_resume_timer = NULL; |
|
|
|
|
router_drain_send_q(rconn); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void router_enqueue_send(struct ETCP_ROUTER_CONN* rconn, const uint8_t* payload, size_t pl_len) { |
|
|
|
|
struct ll_entry* qe = queue_entry_new(0); |
|
|
|
|
if (!qe) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "router_enqueue_send: queue_entry_new failed"); return; } |
|
|
|
|
qe->dgram = u_malloc(pl_len); |
|
|
|
|
if (!qe->dgram) { queue_entry_free(qe); return; } |
|
|
|
|
qe->len = pl_len; |
|
|
|
|
if (pl_len > 0) memcpy(qe->dgram, payload, pl_len); |
|
|
|
|
queue_data_put(rconn->send_q, qe); |
|
|
|
|
rconn->send_blocked = 1; |
|
|
|
|
if (!rconn->send_resume_timer) |
|
|
|
|
rconn->send_resume_timer = uasync_set_timeout(rconn->inst->ua, |
|
|
|
|
ROUTER_SEND_RESUME_TB, rconn, router_send_resume_cb, "router_send_resume"); |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "router_send_q: queued svc_id=%u inflight=%u send_q=%d", |
|
|
|
|
rconn->svc_id, rconn->tx_seq - rconn->rx_acked, queue_entry_count(rconn->send_q)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ====================================================================
|
|
|
|
|
// ACK timers
|
|
|
|
|
// ====================================================================
|
|
|
|
|
@ -83,7 +160,6 @@ static void router_ack_timer_cb(void* arg) {
|
|
|
|
|
router_send_ack(rconn); |
|
|
|
|
rconn->rx_acked = rconn->rx_seq; |
|
|
|
|
} |
|
|
|
|
// перезапускаем если за время ожидания пришли новые данные
|
|
|
|
|
if (rconn->rx_seq != rconn->rx_acked) |
|
|
|
|
rconn->ack_timer = uasync_set_timeout(rconn->inst->ua, |
|
|
|
|
ROUTER_ACK_INTERVAL_TB, rconn, router_ack_timer_cb, "router_ack"); |
|
|
|
|
@ -105,7 +181,7 @@ static void router_idle_ack_timer_cb(void* arg) {
|
|
|
|
|
// Reorder / assembly (аналог etcp_output_try_assembly)
|
|
|
|
|
// ====================================================================
|
|
|
|
|
|
|
|
|
|
static void router_deliver(struct ETCP_ROUTER_CONN* rconn, |
|
|
|
|
static void router_deliver(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn, |
|
|
|
|
const uint8_t* payload, size_t payload_len) { |
|
|
|
|
struct UTUN_INSTANCE* inst = rconn->inst; |
|
|
|
|
etcp_recv_fn cb = inst->router_bindings.callbacks[rconn->svc_id]; |
|
|
|
|
@ -124,16 +200,16 @@ static void router_deliver(struct ETCP_ROUTER_CONN* rconn,
|
|
|
|
|
|
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "router_deliver: svc_id=%u len=%zu from remote=%016llx", |
|
|
|
|
rconn->svc_id, payload_len, (unsigned long long)rconn->remote_node_id); |
|
|
|
|
cb(NULL, svc_entry); |
|
|
|
|
cb(conn, svc_entry); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void router_try_assembly(struct ETCP_ROUTER_CONN* rconn) { |
|
|
|
|
static void router_try_assembly(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* conn) { |
|
|
|
|
uint32_t next = rconn->rx_seq; |
|
|
|
|
while (1) { |
|
|
|
|
struct ll_entry* entry = queue_find_data_by_index(rconn->recv_q, &next); |
|
|
|
|
if (!entry) break; |
|
|
|
|
queue_remove_data(rconn->recv_q, entry); |
|
|
|
|
router_deliver(rconn, entry->dgram, entry->len); |
|
|
|
|
router_deliver(rconn, conn, entry->dgram, entry->len); |
|
|
|
|
rconn->rx_seq = next + 1; |
|
|
|
|
next++; |
|
|
|
|
queue_dgram_free(entry); |
|
|
|
|
@ -160,41 +236,24 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
|
|
|
|
|
|
|
|
|
|
if (hdr->dst_node_id == inst->node_id) { |
|
|
|
|
// ========== Мы — целевая нода ==========
|
|
|
|
|
// Авто-создаём conn при первом пакете
|
|
|
|
|
struct ETCP_ROUTER_CONN* rconn = router_conn_find(inst, hdr->src_node_id, hdr->svc_id); |
|
|
|
|
|
|
|
|
|
if (pl_len == 0) { |
|
|
|
|
// ACK-пакет: обновляем rx_acked и выходим
|
|
|
|
|
// ACK-пакет: обновляем rx_acked, drain send_q, выходим
|
|
|
|
|
if (rconn) { |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "router_ack: recv from %016llx svc_id=%u rx_seq=%u", |
|
|
|
|
(unsigned long long)hdr->src_node_id, hdr->svc_id, hdr->seq); |
|
|
|
|
rconn->rx_acked = hdr->seq; |
|
|
|
|
rconn->last_dgram_ts = get_current_timestamp(); |
|
|
|
|
if (rconn->send_blocked) router_drain_send_q(rconn); |
|
|
|
|
} |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Data-пакет
|
|
|
|
|
// Data-пакет — авто-создаём conn если ещё нет
|
|
|
|
|
if (!rconn) { |
|
|
|
|
// Нет seq-состояния — legacy-доставка напрямую
|
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_router: legacy deliver svc_id=%u from %016llx len=%zu", |
|
|
|
|
hdr->svc_id, (unsigned long long)hdr->src_node_id, pl_len); |
|
|
|
|
etcp_recv_fn cb = inst->router_bindings.callbacks[hdr->svc_id]; |
|
|
|
|
if (cb) { |
|
|
|
|
struct ll_entry* svc_entry = queue_entry_new(0); |
|
|
|
|
if (!svc_entry) { queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
svc_entry->len = 1 + pl_len; |
|
|
|
|
svc_entry->dgram = u_malloc(svc_entry->len); |
|
|
|
|
if (!svc_entry->dgram) { queue_entry_free(svc_entry); queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
svc_entry->dgram[0] = hdr->svc_id; |
|
|
|
|
if (pl_len > 0) memcpy(svc_entry->dgram + 1, pl, pl_len); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); |
|
|
|
|
cb(conn, svc_entry); |
|
|
|
|
} else { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_router: no handler for svc_id=%u", hdr->svc_id); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); |
|
|
|
|
} |
|
|
|
|
return; |
|
|
|
|
rconn = etcp_router_conn_get(inst, hdr->src_node_id, hdr->svc_id); |
|
|
|
|
if (!rconn) { queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Seq-состояние есть — reorder
|
|
|
|
|
@ -221,7 +280,7 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Кладём в recv_q
|
|
|
|
|
struct ll_entry* qe = queue_entry_new(4); // 4 байта data[] для seq
|
|
|
|
|
struct ll_entry* qe = queue_entry_new(4); |
|
|
|
|
if (!qe) { queue_dgram_free(entry); queue_entry_free(entry); return; } |
|
|
|
|
*(uint32_t*)qe->data = seq; |
|
|
|
|
qe->dgram = u_malloc(pl_len); |
|
|
|
|
@ -234,13 +293,10 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
|
|
|
|
|
seq, rconn->rx_seq, queue_entry_count(rconn->recv_q), |
|
|
|
|
(unsigned long long)hdr->src_node_id, rconn->svc_id); |
|
|
|
|
|
|
|
|
|
// Если пришёл ожидаемый — собираем contiguous цепочку
|
|
|
|
|
if (seq == rconn->rx_seq) |
|
|
|
|
router_try_assembly(rconn); |
|
|
|
|
router_try_assembly(rconn, conn); |
|
|
|
|
|
|
|
|
|
// Запускаем/продлеваем ACK таймер
|
|
|
|
|
router_schedule_ack(rconn); |
|
|
|
|
|
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); |
|
|
|
|
} else { |
|
|
|
|
// ========== Транзит ==========
|
|
|
|
|
@ -283,20 +339,23 @@ int etcp_router_init(struct UTUN_INSTANCE* inst) {
|
|
|
|
|
void etcp_router_destroy(struct UTUN_INSTANCE* inst) { |
|
|
|
|
if (!inst) return; |
|
|
|
|
etcp_unbind(inst, ETCP_ID_SVC_ROUTE); |
|
|
|
|
// Очищаем router_conns
|
|
|
|
|
if (inst->router_conns) { |
|
|
|
|
struct ll_entry* entry; |
|
|
|
|
while ((entry = queue_data_get(inst->router_conns)) != NULL) { |
|
|
|
|
struct ETCP_ROUTER_CONN* rconn = (struct ETCP_ROUTER_CONN*)entry; |
|
|
|
|
if (rconn->ack_timer) uasync_cancel_timeout(inst->ua, rconn->ack_timer); |
|
|
|
|
if (rconn->idle_ack_timer) uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); |
|
|
|
|
if (rconn->ack_timer) uasync_cancel_timeout(inst->ua, rconn->ack_timer); |
|
|
|
|
if (rconn->idle_ack_timer) uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); |
|
|
|
|
if (rconn->send_resume_timer) uasync_cancel_timeout(inst->ua, rconn->send_resume_timer); |
|
|
|
|
if (rconn->recv_q) { |
|
|
|
|
struct ll_entry* f; |
|
|
|
|
while ((f = queue_data_get(rconn->recv_q)) != NULL) { |
|
|
|
|
queue_dgram_free(f); queue_entry_free(f); |
|
|
|
|
} |
|
|
|
|
while ((f = queue_data_get(rconn->recv_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); } |
|
|
|
|
queue_free(rconn->recv_q); |
|
|
|
|
} |
|
|
|
|
if (rconn->send_q) { |
|
|
|
|
struct ll_entry* f; |
|
|
|
|
while ((f = queue_data_get(rconn->send_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); } |
|
|
|
|
queue_free(rconn->send_q); |
|
|
|
|
} |
|
|
|
|
queue_entry_free(entry); |
|
|
|
|
} |
|
|
|
|
queue_free(inst->router_conns); |
|
|
|
|
@ -330,8 +389,7 @@ int etcp_router_unbind(struct UTUN_INSTANCE* inst, uint8_t svc_id) {
|
|
|
|
|
int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t dst_node_id, struct ll_entry* entry) { |
|
|
|
|
if (!inst || !entry) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_route_send: NULL inst=%p entry=%p", (void*)inst, (void*)entry); |
|
|
|
|
if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } |
|
|
|
|
return -1; |
|
|
|
|
if (entry) { queue_dgram_free(entry); queue_entry_free(entry); } return -1; |
|
|
|
|
} |
|
|
|
|
if (!entry->dgram || entry->len < 1) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_route_send: empty entry"); queue_dgram_free(entry); queue_entry_free(entry); return -1; |
|
|
|
|
@ -347,35 +405,18 @@ int etcp_route_send(struct UTUN_INSTANCE* inst, uint64_t dst_node_id, struct ll_
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
size_t total_len = SVC_ROUTE_HDR_SIZE + payload_len; |
|
|
|
|
uint8_t* new_dgram = u_malloc(total_len); |
|
|
|
|
if (!new_dgram) { queue_dgram_free(entry); queue_entry_free(entry); return -1; } |
|
|
|
|
|
|
|
|
|
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)new_dgram; |
|
|
|
|
hdr->cmd = ETCP_ID_SVC_ROUTE; |
|
|
|
|
hdr->dst_node_id = dst_node_id; |
|
|
|
|
hdr->src_node_id = inst->node_id; |
|
|
|
|
hdr->seq = 0; // legacy: без seq-трекинга
|
|
|
|
|
hdr->svc_id = svc_id; |
|
|
|
|
if (payload_len > 0) memcpy(new_dgram + SVC_ROUTE_HDR_SIZE, entry->dgram + 1, payload_len); |
|
|
|
|
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, dst_node_id, svc_id); |
|
|
|
|
if (!rconn) { queue_dgram_free(entry); queue_entry_free(entry); return -1; } |
|
|
|
|
|
|
|
|
|
struct ll_entry* new_entry = queue_entry_new(0); |
|
|
|
|
if (!new_entry) { u_free(new_dgram); queue_dgram_free(entry); queue_entry_free(entry); return -1; } |
|
|
|
|
new_entry->dgram = new_dgram; |
|
|
|
|
new_entry->len = total_len; |
|
|
|
|
if (rconn->tx_seq - rconn->rx_acked >= ROUTER_MAX_INFLIGHT) { |
|
|
|
|
router_enqueue_send(rconn, entry->dgram + 1, payload_len); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int ret = router_send_one(rconn, entry->dgram + 1, payload_len); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); |
|
|
|
|
|
|
|
|
|
struct ETCP_CONN* conn = route_bgp_find_conn_for_node(inst->bgp, dst_node_id); |
|
|
|
|
if (!conn) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_route_send: no route to %016llx svc_id=%u, dropping", |
|
|
|
|
(unsigned long long)dst_node_id, svc_id); |
|
|
|
|
queue_entry_free(new_entry); queue_dgram_free(new_entry); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_route_send: svc_id=%u → %016llx via %s len=%zu", |
|
|
|
|
svc_id, (unsigned long long)dst_node_id, conn->log_name, total_len); |
|
|
|
|
return etcp_send(conn, new_entry); |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int etcp_router_input_q_count(struct UTUN_INSTANCE* inst, uint64_t node_id) { |
|
|
|
|
@ -407,12 +448,12 @@ struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst,
|
|
|
|
|
rconn->inst = inst; |
|
|
|
|
rconn->ack_timer = NULL; |
|
|
|
|
rconn->idle_ack_timer = NULL; |
|
|
|
|
rconn->send_blocked = 0; |
|
|
|
|
rconn->send_resume_timer = NULL; |
|
|
|
|
rconn->recv_q = queue_new(inst->ua, ROUTER_RECVQ_HASH_SIZE, 0, 4, "router_recv_q"); |
|
|
|
|
if (!rconn->recv_q) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "router_conn_get: queue_new(recv_q) failed"); |
|
|
|
|
queue_entry_free(&rconn->ll); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
if (!rconn->recv_q) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "router_conn_get: queue_new(recv_q) failed"); queue_entry_free(&rconn->ll); return NULL; } |
|
|
|
|
rconn->send_q = queue_new(inst->ua, 0, 0, 0, "router_send_q"); |
|
|
|
|
if (!rconn->send_q) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "router_conn_get: queue_new(send_q) failed"); queue_free(rconn->recv_q); queue_entry_free(&rconn->ll); return NULL; } |
|
|
|
|
queue_data_put_with_index(inst->router_conns, &rconn->ll); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "router_conn: new conn remote=%016llx svc_id=%u", |
|
|
|
|
(unsigned long long)remote_node_id, svc_id); |
|
|
|
|
@ -426,56 +467,29 @@ int etcp_router_conn_send(struct ETCP_ROUTER_CONN* rconn,
|
|
|
|
|
(void*)rconn, (const void*)data, len); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
// Inflight контроль
|
|
|
|
|
uint32_t inflight = rconn->tx_seq - rconn->rx_acked; |
|
|
|
|
if (inflight >= ROUTER_MAX_INFLIGHT) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "router_conn_send: inflight=%u >= max=%u, drop", |
|
|
|
|
inflight, ROUTER_MAX_INFLIGHT); |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct UTUN_INSTANCE* inst = rconn->inst; |
|
|
|
|
uint32_t seq = rconn->tx_seq++; |
|
|
|
|
|
|
|
|
|
size_t total_len = SVC_ROUTE_HDR_SIZE + len; |
|
|
|
|
uint8_t* dgram = u_malloc(total_len); |
|
|
|
|
if (!dgram) { rconn->tx_seq--; return -1; } |
|
|
|
|
|
|
|
|
|
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)dgram; |
|
|
|
|
hdr->cmd = ETCP_ID_SVC_ROUTE; |
|
|
|
|
hdr->dst_node_id = rconn->remote_node_id; |
|
|
|
|
hdr->src_node_id = inst->node_id; |
|
|
|
|
hdr->seq = seq; |
|
|
|
|
hdr->svc_id = rconn->svc_id; |
|
|
|
|
memcpy(dgram + SVC_ROUTE_HDR_SIZE, data, len); |
|
|
|
|
|
|
|
|
|
struct ll_entry* entry = queue_entry_new(0); |
|
|
|
|
if (!entry) { u_free(dgram); rconn->tx_seq--; return -1; } |
|
|
|
|
entry->dgram = dgram; |
|
|
|
|
entry->len = total_len; |
|
|
|
|
|
|
|
|
|
struct ETCP_CONN* conn = route_bgp_find_conn_for_node(inst->bgp, rconn->remote_node_id); |
|
|
|
|
if (!conn) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "router_conn_send: no route to %016llx svc_id=%u", |
|
|
|
|
(unsigned long long)rconn->remote_node_id, rconn->svc_id); |
|
|
|
|
queue_entry_free(entry); queue_dgram_free(entry); rconn->tx_seq--; return -1; |
|
|
|
|
if (rconn->tx_seq - rconn->rx_acked >= ROUTER_MAX_INFLIGHT) { |
|
|
|
|
router_enqueue_send(rconn, data, len); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
rconn->last_dgram_ts = get_current_timestamp(); |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "router_conn_send: seq=%u → %016llx svc_id=%u len=%zu inflight=%u", |
|
|
|
|
seq, (unsigned long long)rconn->remote_node_id, rconn->svc_id, len, inflight + 1); |
|
|
|
|
return etcp_send(conn, entry); |
|
|
|
|
return router_send_one(rconn, data, len); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void etcp_router_conn_close(struct ETCP_ROUTER_CONN* rconn) { |
|
|
|
|
if (!rconn) return; |
|
|
|
|
struct UTUN_INSTANCE* inst = rconn->inst; |
|
|
|
|
if (rconn->ack_timer) uasync_cancel_timeout(inst->ua, rconn->ack_timer); |
|
|
|
|
if (rconn->idle_ack_timer) uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); |
|
|
|
|
if (rconn->ack_timer) uasync_cancel_timeout(inst->ua, rconn->ack_timer); |
|
|
|
|
if (rconn->idle_ack_timer) uasync_cancel_timeout(inst->ua, rconn->idle_ack_timer); |
|
|
|
|
if (rconn->send_resume_timer) uasync_cancel_timeout(inst->ua, rconn->send_resume_timer); |
|
|
|
|
if (rconn->recv_q) { |
|
|
|
|
struct ll_entry* f; |
|
|
|
|
while ((f = queue_data_get(rconn->recv_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); } |
|
|
|
|
queue_free(rconn->recv_q); |
|
|
|
|
} |
|
|
|
|
if (rconn->send_q) { |
|
|
|
|
struct ll_entry* f; |
|
|
|
|
while ((f = queue_data_get(rconn->send_q)) != NULL) { queue_dgram_free(f); queue_entry_free(f); } |
|
|
|
|
queue_free(rconn->send_q); |
|
|
|
|
} |
|
|
|
|
if (inst->router_conns) |
|
|
|
|
queue_remove_data(inst->router_conns, &rconn->ll); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "router_conn: closed remote=%016llx svc_id=%u", |
|
|
|
|
|