Prepare BGP paths before committing received node state

This commit is contained in:
evgeny committed 2026-10-24 15:50:17 +02:00
1 parent ab5c077600
commit 145dd1e5ab
2 files changed
+40 -25

No files matched your search

+38 -24
View File
@@ -52,7 +52,7 @@ static int topo_tx_control(struct TOPO_GROUP_CONN_ITEM* peer, const void* data,
static int topo_tx_node(struct TOPO_GROUP_CONN_ITEM* peer, uint64_t node_id);
static int topo_tx_table(struct TOPO_GROUP_CONN_ITEM* peer);
static int topo_control_wait(struct ETCP_CONN* conn, const void* data, size_t size);
static void topo_group_routes_changed(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, int event);
static int topo_group_routes_changed(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, int event);
static void topo_group_prune_paths(struct TOPO_GROUP_CONN_ITEM* peer, int all);
static void topo_exchange_watch(void* arg);
static void topo_tx_fail(struct TOPO_GROUP_CONN_ITEM* peer);
@@ -1191,8 +1191,9 @@ int topo_group_remove_path(struct TOPO_GROUP_NODE* nq, struct ETCP_CONN* conn) {
}
/* Одна точка обновления доступности, потребителей и анонсов после изменения путей. */
static void topo_group_routes_changed(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, int event) {
static int topo_group_routes_changed(struct TOPO_GROUP* group, struct TOPO_GROUP_NODE* node, int event) {
uint64_t id = node->node_id;
int result = 0;
struct TOPO_NODEPATH* best = topo_node_best_path(node);
node->conn_presence &= ~(NCONN_BGP | NCONN_DIRECT);
node->conn_up &= ~(NCONN_BGP | NCONN_DIRECT);
@@ -1211,9 +1212,11 @@ static void topo_group_routes_changed(struct TOPO_GROUP* group, struct TOPO_GROU
(unsigned long long)(best ? best->conn->peer_node_id : 0), best ? best->hop_count : 0);
if (group->group_type != TOPO_GROUP_TYPE_CHAT && group->instance->rt) {
route_delete(group->instance->rt, node);
if (best && node->subnets && node->subnets->v4_subnets && !route_insert(group->instance->rt, node))
if (best && node->subnets && node->subnets->v4_subnets && !route_insert(group->instance->rt, node)) {
result = -1;
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "BGP IPv4 routes rejected: group=%016llx node=%016llx; previous routes removed",
(unsigned long long)group->group_id, (unsigned long long)id);
}
}
topo_fire_nodeinfo_cbk(group->instance, group, node);
if (!node->paths) {
@@ -1226,6 +1229,7 @@ static void topo_group_routes_changed(struct TOPO_GROUP* group, struct TOPO_GROU
topo_recovery_changed(group);
conn_mgr_routes_changed(group->conn_mgr);
multicast_routes_changed(group->instance);
return result;
}
/* TABLE_COMPLETE подтверждает только NODEINFO текущего обмена. Сбой обмена
@@ -1374,9 +1378,9 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
if (result < 0) return -1;
struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, from->peer_node_id);
((struct TOPO_NODEPATH*)nodeinfo1->paths->tail)->exchange = peer ? peer->local_epoch : 0;
topo_group_routes_changed(group, nodeinfo1, TOPO_NODE_EVENT_UPDATE);
result = topo_group_routes_changed(group, nodeinfo1, TOPO_NODE_EVENT_UPDATE);
topo_group_peer_progressed(group, from->peer_node_id);
return 0;
return result;
}
uint64_t incoming_timestamp = new_ni->timestamp;
if (!nodeinfo1) {
@@ -1391,9 +1395,22 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
nodeinfo1 = (struct TOPO_GROUP_NODE*)qe;
memset((uint8_t*)nodeinfo1 + sizeof(struct ll_entry), 0, sizeof(*nodeinfo1) - sizeof(struct ll_entry));
}
/* Подготовить новый путь до изменения записи/подсетей. OOM сохраняет прежний узел целиком. */
uint64_t hop_list[MAX_HOPS];
if (new_hop_count) memcpy(hop_list, new_hop_list, new_hop_count * sizeof(*hop_list));
hop_list[new_hop_count] = from->peer_node_id;
struct TOPO_GROUP_NODE prepared = {0};
if (topo_group_add_path(&prepared, from, hop_list, new_hop_count + 1, incoming_cumulative_rtt) < 0) {
topo_node_destroy(group->instance->topo_groups, new_ni);
struct TOPO_GROUP_NODE rejected = { .subnets = new_subnets };
topo_nodeq_free_group_fields(group->instance->topo_groups, &rejected);
if (is_new_node) queue_entry_free(&nodeinfo1->ll);
u_free(new_hop_list); return -1;
}
struct TOPO_NODE* stored = topo_node_registry_store(group->instance->topo_groups, new_ni);
if (!stored) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node registry update failed");
topo_nodeq_clear_paths(&prepared);
topo_node_destroy(group->instance->topo_groups, new_ni);
struct TOPO_GROUP_NODE rejected = { .subnets = new_subnets };
topo_nodeq_free_group_fields(group->instance->topo_groups, &rejected);
@@ -1409,24 +1426,24 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
DEBUG_INFO(DEBUG_CATEGORY_BGP, "node added to group: node=%016llx grp=%016llx type=%u ch=%s (bgp)",
(unsigned long long)node_id, (unsigned long long)group->group_id, group->group_type, group->channel_id);
nodeinfo1->paths = paths; nodeinfo1->last_ver = new_ver;
/* Остальные соседи сохраняются; после store больше не нужны выделения памяти. */
struct TOPO_NODEPATH* incoming = (struct TOPO_NODEPATH*)prepared.paths->head;
struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, from->peer_node_id);
incoming->exchange = peer ? peer->local_epoch : 0;
if (paths) {
struct ll_entry* e;
while ((e = queue_data_get(paths))) {
if (((struct TOPO_NODEPATH*)e)->conn == from) queue_entry_free(e);
else queue_data_put(prepared.paths, e);
}
queue_free(paths);
}
nodeinfo1->paths = prepared.paths; nodeinfo1->last_ver = new_ver;
nodeinfo1->last_timestamp = incoming_timestamp;
nodeinfo1->radio = (ni->flags & TOPO_FLAG_RADIO) ? 1 : 0;
nodeinfo1->phone_status = ni->flags & (TOPO_FLAG_PHONE_KNOWN | TOPO_FLAG_PHONE_BUSY);
uint64_t hop_list[MAX_HOPS];
if (new_hop_count > 0) memcpy(hop_list, new_hop_list, new_hop_count * 8);
hop_list[new_hop_count] = from->peer_node_id;
uint8_t extended_count = new_hop_count + 1;
u_free(new_hop_list);
if (topo_group_add_path(nodeinfo1, from, hop_list, extended_count, incoming_cumulative_rtt) < 0) {
if (is_new_node) topo_nodeq_remove_node(group, nodeinfo1);
return -1;
}
struct TOPO_GROUP_CONN_ITEM* peer = topo_group_peer(group, from->peer_node_id);
((struct TOPO_NODEPATH*)nodeinfo1->paths->tail)->exchange = peer ? peer->local_epoch : 0;
if (node_id != group->instance->node_id) {
sqlite3* sdb = group->instance->topo_sqlite_db;
if (sdb) {
@@ -1448,12 +1465,9 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
if (group->instance->topo_groups->node_updated_cb)
group->instance->topo_groups->node_updated_cb(group->instance, node_id, ni->public_key, ni->ed25519_public_key);
topo_group_routes_changed(group, nodeinfo1, is_new_node ? TOPO_NODE_EVENT_NEW : TOPO_NODE_EVENT_UPDATE);
int result = topo_group_routes_changed(group, nodeinfo1, is_new_node ? TOPO_NODE_EVENT_NEW : TOPO_NODE_EVENT_UPDATE);
int socks_changed = 1;
if (!is_new_node) socks_changed = 1;
if (node_id != group->instance->node_id && (is_new_node || socks_changed)) {
if (node_id != group->instance->node_id) {
struct TOPO_NODE* tni = topo_node_registry_find(group->instance->topo_groups, nodeinfo1->node_id);
int v4a = tni ? topo_list_count((struct _topo_head*)tni->v4_addrs) : 0;
int v6a = tni ? topo_list_count((struct _topo_head*)tni->v6_addrs) : 0;
@@ -1464,7 +1478,7 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
topo_group_peer_progressed(group, from->peer_node_id);
node_conn_direct_update_node(group->instance, node_id);
return 0;
return result;
}
/* Обрабатывает WITHDRAW: удаляет узел/пути, чистит роутинг, форвардит withdraw. */
+2 -1
View File
@@ -1102,7 +1102,8 @@ int topo_node_init_self(struct UTUN_INSTANCE* instance) {
topo_node_destroy(instance->topo_groups, ni); return -1;
}
if (!topo_node_registry_store(instance->topo_groups, ni)) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot register local identity"); return -1;
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot register local identity");
topo_node_destroy(instance->topo_groups, ni); return -1;
}
return 0;
}