Track topology exchange readiness per group and peer
This commit is contained in:
1 parent
bce17d9cfc
commit
66c59501fc
14 files changed
+260
-108
No files matched your search
@@ -37,19 +37,47 @@
|
||||
// Вспомогательные функции
|
||||
// ============================================================================
|
||||
|
||||
static struct TOPO_GROUP_CONN_ITEM* topo_group_peer(const struct TOPO_GROUP* group, uint64_t peer_id) {
|
||||
for (struct ll_entry* e = group && group->senders_list ? group->senders_list->head : NULL; e; e = e->next) {
|
||||
struct TOPO_GROUP_CONN_ITEM* item = (struct TOPO_GROUP_CONN_ITEM*)e->data;
|
||||
if (item->conn && item->conn->peer_node_id == peer_id) return item;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int topo_group_peer_ready(const struct TOPO_GROUP* group, uint64_t peer_id) {
|
||||
const struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, peer_id);
|
||||
return peer && peer->conn->links_up && peer->table_received && peer->table_sent;
|
||||
}
|
||||
|
||||
static void topo_group_log_exchange(struct TOPO_GROUP* group, struct TOPO_GROUP_CONN_ITEM* peer) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "group exchange: group=%016llx peer=%016llx exchange=%016llx sent=%u received=%u ready=%d",
|
||||
(unsigned long long)group->group_id, (unsigned long long)peer->conn->peer_node_id,
|
||||
(unsigned long long)peer->exchange_id, peer->table_sent, peer->table_received,
|
||||
topo_group_peer_ready(group, peer->conn->peer_node_id));
|
||||
}
|
||||
|
||||
/* Шлёт пиру запрос полной таблицы узлов группы (REQUEST_TABLE). */
|
||||
static void topo_group_send_table_request(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
if (!group || !conn) return;
|
||||
struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, conn->peer_node_id);
|
||||
if (!peer || peer->conn != conn) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "table request without group peer"); return; }
|
||||
if (!peer->exchange_id && (random_bytes((uint8_t*)&peer->exchange_id, sizeof(peer->exchange_id)) != 0 || !peer->exchange_id)) {
|
||||
peer->exchange_id = 0;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot generate group exchange id group=%016llx", (unsigned long long)group->group_id);
|
||||
return;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "Sending table request to %s grp=%016llx", conn->log_name, (unsigned long long)group->group_id);
|
||||
struct TOPOMSG_TABLE_REQ* req = u_calloc(1, sizeof(struct TOPOMSG_TABLE_REQ));
|
||||
if (!req) return;
|
||||
if (!req) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "table request allocation failed"); return; }
|
||||
req->cmd = ETCP_ID_TOPO_ENTRY;
|
||||
req->subcmd = TOPO_SUBCMD_REQUEST_TABLE;
|
||||
req->group_id = group->group_id;
|
||||
req->exchange_id = peer->exchange_id;
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { u_free(req); return; }
|
||||
if (!e) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "table request entry allocation failed"); u_free(req); return; }
|
||||
e->dgram = (uint8_t*)req; e->len = sizeof(struct TOPOMSG_TABLE_REQ);
|
||||
if (etcp_send(conn, e) != 0) { u_free(req); queue_entry_free(e); }
|
||||
if (etcp_send(conn, e) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot send table request"); u_free(req); queue_entry_free(e); }
|
||||
}
|
||||
|
||||
/* Запрашивает у пира членство в группе (JOIN_GROUP). */
|
||||
@@ -82,32 +110,37 @@ static void topo_group_send_resync(struct ETCP_CONN* conn) {
|
||||
}
|
||||
|
||||
/* Сигнализирует пиру об окончании начальной синхронизации таблицы. */
|
||||
static void topo_group_send_table_complete(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
if (!group || !conn) return;
|
||||
static int topo_group_send_table_complete(struct TOPO_GROUP* group, struct ETCP_CONN* conn, uint64_t exchange_id) {
|
||||
struct TOPOMSG_TABLE_REQ* req = u_calloc(1, sizeof(struct TOPOMSG_TABLE_REQ));
|
||||
if (!req) return;
|
||||
if (!req) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "table complete allocation failed"); return -1; }
|
||||
req->cmd = ETCP_ID_TOPO_ENTRY;
|
||||
req->subcmd = TOPO_SUBCMD_TABLE_COMPLETE;
|
||||
req->group_id = group->group_id;
|
||||
req->exchange_id = exchange_id;
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { u_free(req); return; }
|
||||
if (!e) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "table complete entry allocation failed"); u_free(req); return -1; }
|
||||
e->dgram = (uint8_t*)req; e->len = sizeof(struct TOPOMSG_TABLE_REQ);
|
||||
if (etcp_send(conn, e) != 0) { u_free(req); queue_entry_free(e); }
|
||||
if (etcp_send(conn, e) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot send table complete"); u_free(req); queue_entry_free(e); return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int topo_group_add_to_senders(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
static bool topo_group_should_send_to(const struct TOPO_GROUP_NODE* nq, uint64_t target_id);
|
||||
static void topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
static int topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn, uint64_t exchange_id);
|
||||
static void topo_group_handle_join_group(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
static void topo_group_send_resync(struct ETCP_CONN* conn);
|
||||
static void topo_group_handle_resync(struct UTUN_INSTANCE* instance, struct ETCP_CONN* conn);
|
||||
|
||||
/* Запоминает REQUEST_TABLE для группы, которой у нас ещё нет (CHAT-канал не загружен). */
|
||||
static void topo_group_remember_table_req(struct TOPO_GROUPS* g, uint64_t node_id, uint64_t group_id) {
|
||||
static void topo_group_remember_table_req(struct TOPO_GROUPS* g, uint64_t node_id, uint64_t group_id, uint64_t exchange_id) {
|
||||
if (!g) return;
|
||||
for (int i = 0; i < g->pending_table_req_count; i++)
|
||||
if (g->pending_table_reqs[i].node_id == node_id && g->pending_table_reqs[i].group_id == group_id) return;
|
||||
if (g->pending_table_reqs[i].node_id == node_id && g->pending_table_reqs[i].group_id == group_id) {
|
||||
g->pending_table_reqs[i].exchange_id = exchange_id; return;
|
||||
}
|
||||
if (g->pending_table_req_count >= TOPO_MAX_PENDING_TABLE_REQS) {
|
||||
memmove(g->pending_table_reqs, g->pending_table_reqs + 1,
|
||||
(TOPO_MAX_PENDING_TABLE_REQS - 1) * sizeof(g->pending_table_reqs[0]));
|
||||
@@ -115,6 +148,7 @@ static void topo_group_remember_table_req(struct TOPO_GROUPS* g, uint64_t node_i
|
||||
}
|
||||
g->pending_table_reqs[g->pending_table_req_count].node_id = node_id;
|
||||
g->pending_table_reqs[g->pending_table_req_count].group_id = group_id;
|
||||
g->pending_table_reqs[g->pending_table_req_count].exchange_id = exchange_id;
|
||||
g->pending_table_req_count++;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "remembered table request node=%016llx grp=%016llx (group not created yet)",
|
||||
(unsigned long long)node_id, (unsigned long long)group_id);
|
||||
@@ -133,7 +167,7 @@ static void topo_group_fulfill_table_reqs(struct TOPO_GROUPS* g, uint64_t group_
|
||||
if (conn && conn->links_up) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "fulfilling remembered table request node=%016llx grp=%016llx",
|
||||
(unsigned long long)req->node_id, (unsigned long long)group_id);
|
||||
topo_group_handle_request_table(group, conn);
|
||||
topo_group_handle_request_table(group, conn, req->exchange_id);
|
||||
}
|
||||
}
|
||||
g->pending_table_req_count = w;
|
||||
@@ -259,6 +293,13 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return;
|
||||
}
|
||||
|
||||
if ((subcmd == TOPO_SUBCMD_REQUEST_TABLE || subcmd == TOPO_SUBCMD_TABLE_COMPLETE) &&
|
||||
(entry->len != sizeof(struct TOPOMSG_TABLE_REQ) || !((struct TOPOMSG_TABLE_REQ*)data)->exchange_id)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_BGP, "invalid table control peer=%016llx cmd=%u length=%u",
|
||||
(unsigned long long)from_conn->peer_node_id, subcmd, entry->len);
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return;
|
||||
}
|
||||
|
||||
uint64_t pkt_group_id = 0;
|
||||
if (subcmd == TOPO_SUBCMD_NODEINFO && entry->len >= sizeof(struct TOPOMSG_NODEINFO_PKT)) {
|
||||
pkt_group_id = ((struct TOPOMSG_NODEINFO_PKT*)data)->node.group_id;
|
||||
@@ -278,7 +319,8 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
|
||||
struct TOPO_GROUP* group = topo_groups_find(instance->topo_groups, pkt_group_id);
|
||||
if (!group) {
|
||||
if (subcmd == TOPO_SUBCMD_REQUEST_TABLE)
|
||||
topo_group_remember_table_req(instance->topo_groups, from_conn->peer_node_id, pkt_group_id);
|
||||
topo_group_remember_table_req(instance->topo_groups, from_conn->peer_node_id, pkt_group_id,
|
||||
((struct TOPOMSG_TABLE_REQ*)data)->exchange_id);
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "BGP recv %s from %s: group %016llx not found, dropping", group_subcmd_name(subcmd), from_conn->log_name, (unsigned long long)pkt_group_id);
|
||||
queue_dgram_free(entry); queue_entry_free(entry); return;
|
||||
}
|
||||
@@ -302,14 +344,25 @@ static void topo_group_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
|
||||
|
||||
if (subcmd == TOPO_SUBCMD_NODEINFO) { nodeinfo_dump_log(data, entry->len); topo_group_process_nodeinfo(group, from_conn, data, entry->len); }
|
||||
else if (subcmd == TOPO_SUBCMD_WITHDRAW) topo_group_process_withdraw(group, from_conn, data, entry->len);
|
||||
else if (subcmd == TOPO_SUBCMD_REQUEST_TABLE) topo_group_handle_request_table(group, from_conn);
|
||||
else if (subcmd == TOPO_SUBCMD_REQUEST_TABLE)
|
||||
topo_group_handle_request_table(group, from_conn, ((struct TOPOMSG_TABLE_REQ*)data)->exchange_id);
|
||||
else if (subcmd == TOPO_SUBCMD_JOIN_GROUP) topo_group_handle_join_group(group, from_conn);
|
||||
else if (subcmd == TOPO_SUBCMD_LEAVE_GROUP) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "peer left group: peer=%016llx group=%016llx",
|
||||
(unsigned long long)from_conn->peer_node_id, (unsigned long long)group->group_id);
|
||||
topo_group_remove_conn(group, from_conn, TOPO_REMOVE_REMOTE_LEAVE);
|
||||
}
|
||||
else if (subcmd == TOPO_SUBCMD_TABLE_COMPLETE) { etcp_set_routing_exchange_state(from_conn, 3); DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP sync complete with %s: %d nodes grp=%016llx", from_conn->log_name, queue_entry_count(group->nodes), (unsigned long long)group->group_id); }
|
||||
else if (subcmd == TOPO_SUBCMD_TABLE_COMPLETE) {
|
||||
struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, from_conn->peer_node_id);
|
||||
uint64_t id = ((struct TOPOMSG_TABLE_REQ*)data)->exchange_id;
|
||||
if (!peer || peer->conn != from_conn || peer->exchange_id != id) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "ignore stale TABLE_COMPLETE group=%016llx peer=%016llx exchange=%016llx",
|
||||
(unsigned long long)group->group_id, (unsigned long long)from_conn->peer_node_id, (unsigned long long)id);
|
||||
} else if (!peer->table_received) {
|
||||
peer->table_received = 1;
|
||||
topo_group_log_exchange(group, peer);
|
||||
}
|
||||
}
|
||||
else if (subcmd == TOPO_SUBCMD_ERR_GROUP_MISMATCH) {
|
||||
if (entry->len >= sizeof(struct TOPOMSG_ERR_GROUP_MISMATCH)) {
|
||||
struct TOPOMSG_ERR_GROUP_MISMATCH* err = (struct TOPOMSG_ERR_GROUP_MISMATCH*)data;
|
||||
@@ -336,7 +389,9 @@ static void topo_group_conn_status(struct ETCP_CONN* conn, int status, void* arg
|
||||
for (struct ll_entry* e = groups->group_list->head; e; e = e->next) {
|
||||
struct TOPO_GROUP* g = (struct TOPO_GROUP*)e;
|
||||
for (struct ll_entry* se = g->senders_list->head; se; se = se->next) {
|
||||
if (((struct TOPO_GROUP_CONN_ITEM*)se->data)->conn != conn) continue;
|
||||
struct TOPO_GROUP_CONN_ITEM* peer = (struct TOPO_GROUP_CONN_ITEM*)se->data;
|
||||
if (peer->conn != conn) continue;
|
||||
peer->exchange_id = 0; peer->table_received = 0; peer->table_sent = 0;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP,"BGP session resync: peer=%016llx group=%016llx",
|
||||
(unsigned long long)conn->peer_node_id,(unsigned long long)g->group_id);
|
||||
topo_group_send_join_group(g,conn); topo_group_send_table_request(g,conn);
|
||||
@@ -1163,12 +1218,12 @@ int topo_group_process_withdraw(struct TOPO_GROUP* group, struct ETCP_CONN* send
|
||||
}
|
||||
|
||||
/* Сериализует и шлёт NODEINFO узла конкретному пиру. */
|
||||
void topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt) {
|
||||
if (!group || !node || !conn) return;
|
||||
int topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt) {
|
||||
if (!group || !node || !conn) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "send_nodeinfo: invalid arguments"); return -1; }
|
||||
|
||||
size_t max_sz = sizeof(struct TOPOMSG_NODEINFO_PKT) + TOPO_NODE_WIRE_MAX_SIZE;
|
||||
uint8_t* p = u_malloc(max_sz);
|
||||
if (!p) return;
|
||||
if (!p) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "send_nodeinfo: allocation failed"); return -1; }
|
||||
|
||||
p[0] = ETCP_ID_TOPO_ENTRY; p[1] = TOPO_SUBCMD_NODEINFO;
|
||||
|
||||
@@ -1183,18 +1238,26 @@ void topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE*
|
||||
node->paths ? queue_entry_count(node->paths) : -1,
|
||||
group->nodes ? queue_entry_count(group->nodes) : -1);
|
||||
u_free(p);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "send_nodeinfo: node %016llx ver=%d grp=%016llx to conn=%p name='%s'", (unsigned long long)node->node_id, sni->ver, (unsigned long long)group->group_id, (void*)conn, conn->log_name);
|
||||
uint8_t sflags = (group->group_type == TOPO_GROUP_TYPE_CHAT) ? 0 : TOPO_FLAG_SEND_SUBNETS;
|
||||
int ser_len = topo_node_serialize(sni, node, group->group_id, sflags, p + 2, max_sz - 2, cumulative_rtt);
|
||||
if (ser_len < 0) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "send_nodeinfo: serialize failed for node %016llx", (unsigned long long)node->node_id); u_free(p); return; }
|
||||
if (ser_len < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "send_nodeinfo: serialize failed for node %016llx", (unsigned long long)node->node_id);
|
||||
u_free(p); return -1;
|
||||
}
|
||||
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { u_free(p); return; }
|
||||
if (!e) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "send_nodeinfo: entry allocation failed"); u_free(p); return -1; }
|
||||
e->dgram = p; e->len = (size_t)ser_len + 2;
|
||||
|
||||
if (etcp_send(conn, e) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "send_nodeinfo: etcp_send FAILED for node %016llx to %s", (unsigned long long)node->node_id, conn->log_name); u_free(p); queue_entry_free(e); }
|
||||
if (etcp_send(conn, e) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "send_nodeinfo: etcp_send FAILED for node %016llx to %s",
|
||||
(unsigned long long)node->node_id, conn->log_name);
|
||||
u_free(p); queue_entry_free(e); return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Добавляет conn в senders_list (дедуп), если его там ещё нет. */
|
||||
@@ -1315,32 +1378,37 @@ int topo_group_leave_peer(struct TOPO_GROUP* group, struct NODE_CONN_DIRECT* han
|
||||
}
|
||||
|
||||
/* Шлёт пиру полную таблицу узлов группы (все узлы, кроме достижимых через него). */
|
||||
static void topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
if (!group || !conn) return;
|
||||
static int topo_group_send_full_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
uint64_t target = conn->peer_node_id;
|
||||
struct ll_entry* e = group->nodes ? group->nodes->head : NULL;
|
||||
while (e) {
|
||||
struct TOPO_GROUP_NODE* nq = (struct TOPO_GROUP_NODE*)e;
|
||||
if (nq->node_id == group->instance->node_id) { e = e->next; continue; }
|
||||
if (!nq->paths) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "node has no paths"); e = e->next; continue; }
|
||||
if (topo_group_should_send_to(nq, target)) topo_group_send_nodeinfo(group, nq, conn, topo_get_chain_rtt(nq));
|
||||
if (topo_group_should_send_to(nq, target) && topo_group_send_nodeinfo(group, nq, conn, topo_get_chain_rtt(nq)) < 0) return -1;
|
||||
e = e->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Обрабатывает REQUEST_TABLE: шлёт свой nodeinfo + полную таблицу + TABLE_COMPLETE. */
|
||||
static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn) {
|
||||
static void topo_group_handle_request_table(struct TOPO_GROUP* group, struct ETCP_CONN* conn, uint64_t exchange_id) {
|
||||
if (!group || !conn) return;
|
||||
if (!topo_group_peer_allowed(group, conn->peer_node_id)) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "table request deferred: member unknown peer=%016llx group=%016llx",
|
||||
(unsigned long long)conn->peer_node_id, (unsigned long long)group->group_id);
|
||||
return;
|
||||
}
|
||||
topo_group_send_nodeinfo(group, group->local_node, conn, 0);
|
||||
topo_group_send_full_table(group, conn);
|
||||
if (topo_group_send_nodeinfo(group, group->local_node, conn, 0) < 0 || topo_group_send_full_table(group, conn) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "table exchange incomplete group=%016llx peer=%016llx exchange=%016llx",
|
||||
(unsigned long long)group->group_id, (unsigned long long)conn->peer_node_id, (unsigned long long)exchange_id);
|
||||
return;
|
||||
}
|
||||
/* senders_list заполняется только через topo_group_new_conn (add + BGP);
|
||||
здесь не добавляем, иначе new_conn (на JOIN_GROUP) упирается в дедуп и не шлёт TABLE_REQ обратно. */
|
||||
topo_group_send_table_complete(group, conn);
|
||||
if (topo_group_send_table_complete(group, conn, exchange_id) < 0) return;
|
||||
struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, conn->peer_node_id);
|
||||
if (peer && peer->conn == conn && !peer->table_sent) { peer->table_sent = 1; topo_group_log_exchange(group, peer); }
|
||||
}
|
||||
|
||||
/* Обрабатывает JOIN_GROUP: для UTUN — добавить запросившего и инициировать BGP обратно. */
|
||||
|
||||
@@ -98,6 +98,12 @@ void topo_fire_nodeinfo_cbk(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* g
|
||||
* JOIN_READY из chat_sync.h — результат добавления участника, а TABLE_COMPLETE —
|
||||
* результат обмена топологией одной группы; ни один не означает готовности других групп.
|
||||
* Конфиг, auto-connect и recovery обязаны использовать общую проверку членства.
|
||||
*
|
||||
* REQUEST_TABLE содержит ненулевой exchange_id, сгенерированный запросившей
|
||||
* стороной для текущего обмена (группа, пир). TABLE_COMPLETE возвращает тот же
|
||||
* id только после успешной постановки всех NODEINFO в транспорт. Дубликаты
|
||||
* запроса используют прежний id; новое присоединение и REINIT создают новый.
|
||||
* Ответ с другим id не завершает текущий обмен. Формат изменён без совместимости.
|
||||
*/
|
||||
|
||||
// Sub-команды
|
||||
@@ -140,6 +146,7 @@ struct TOPOMSG_TABLE_REQ {
|
||||
uint8_t cmd;
|
||||
uint8_t subcmd;
|
||||
uint64_t group_id; // идентификатор группы
|
||||
uint64_t exchange_id; // ненулевой id запроса; TABLE_COMPLETE возвращает его без изменений
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
@@ -173,9 +180,11 @@ struct TOPOMSG_ERR_GROUP_MISMATCH {
|
||||
} __attribute__((packed));
|
||||
|
||||
struct TOPO_GROUP_CONN_ITEM {
|
||||
struct ll_entry ll;
|
||||
struct ETCP_CONN* conn;
|
||||
struct NODE_CONN_DIRECT* handle; // владение BGP этим conn (NCD-handle)
|
||||
uint64_t exchange_id; // текущий исходящий REQUEST_TABLE
|
||||
uint8_t table_received; // TABLE_COMPLETE для exchange_id принят
|
||||
uint8_t table_sent; // ответ на запрос пира целиком передан транспорту
|
||||
};
|
||||
|
||||
struct ETCP_LINK;
|
||||
@@ -194,7 +203,7 @@ struct TOPO_GROUP {
|
||||
uint64_t group_id; // уникальный идентификатор группы
|
||||
uint8_t group_type; // TOPO_GROUP_TYPE_*
|
||||
struct UTUN_INSTANCE* instance;
|
||||
struct ll_queue* senders_list; // TOPO_GROUP_CONN_ITEM{ll_entry,ETCP_CONN*} — активные BGP-пиры, без хеш-индекса
|
||||
struct ll_queue* senders_list; // ll_entry.data = TOPO_GROUP_CONN_ITEM, без хеш-индекса
|
||||
struct ll_queue* nodes; // TOPO_GROUP_NODE{ll_entry,node_id,paths,...} — per-group узлы, хеш-индекс по node_id(8B)
|
||||
struct TOPO_GROUP_NODE* local_node; // свой узел в этой группе
|
||||
uint8_t ed25519_public_key[SC_PUBKEY_SIZE];
|
||||
@@ -215,6 +224,7 @@ struct TOPO_GROUP {
|
||||
struct topo_pending_table_req {
|
||||
uint64_t node_id; /* кто запросил таблицу */
|
||||
uint64_t group_id; /* какую группу */
|
||||
uint64_t exchange_id;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -294,6 +304,13 @@ void topo_groups_remove_group(struct TOPO_GROUPS* g, uint64_t group_id);
|
||||
*/
|
||||
int topo_group_new_conn(struct TOPO_GROUP* group, struct ETCP_CONN* conn);
|
||||
|
||||
/* Готовность относится только к паре (group, peer): собственный снимок отправлен,
|
||||
* снимок пира принят до TABLE_COMPLETE текущего REQUEST_TABLE. Транспортный UP
|
||||
* этого не гарантирует. Повторное new_conn не сбрасывает готовность; REINIT
|
||||
* начинает новый обмен с новым exchange_id. Старый TABLE_COMPLETE игнорируется.
|
||||
* Это состояние обмена таблицами, а не добавление мембера (см. chat_join.h). */
|
||||
int topo_group_peer_ready(const struct TOPO_GROUP* group, uint64_t peer_id);
|
||||
|
||||
/**
|
||||
* @brief Удаляет conn из senders_list, очищает paths во всех nodes, отправляет withdraw если node unreachable.
|
||||
*
|
||||
@@ -332,7 +349,7 @@ int topo_group_process_withdraw(struct TOPO_GROUP* group, struct ETCP_CONN* send
|
||||
/**
|
||||
* @brief Отправляет NODEINFO пакет одному conn (всегда local_node).
|
||||
*/
|
||||
void topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt);
|
||||
int topo_group_send_nodeinfo(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, struct ETCP_CONN* conn, uint16_t cumulative_rtt);
|
||||
|
||||
/**
|
||||
* @brief Отправляет WITHDRAW для node_id (вызывает broadcast_withdraw).
|
||||
|
||||
Reference in new issue
Block a user