From d1562bdd0ee82c80f0e2c4f61b610fcf5b25568f Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 15:51:43 +0200 Subject: [PATCH] Check that late BGP allocation failure preserves accepted state --- tests/Makefile.am | 3 +++ tests/test_group_exchange.c | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index 98f8bfb3..a4cbffcc 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -707,6 +707,9 @@ test_group_ownership_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS) test_group_exchange_SOURCES = test_group_exchange.c test_group_exchange_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib test_group_exchange_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS) +if OS_LINUX +test_group_exchange_LDFLAGS = -Wl,--wrap=queue_entry_new +endif test_bgp_paths_SOURCES = test_bgp_paths.c test_bgp_paths_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib diff --git a/tests/test_group_exchange.c b/tests/test_group_exchange.c index 5fa188c8..fdd67aa4 100644 --- a/tests/test_group_exchange.c +++ b/tests/test_group_exchange.c @@ -10,6 +10,18 @@ #include "../lib/debug_config.h" #include "../lib/platform_compat.h" +#ifdef __linux__ +static int fail_path; +struct ll_entry* __real_queue_entry_new(size_t); +struct ll_entry* __wrap_queue_entry_new(size_t size) { + if (fail_path && size == sizeof(struct TOPO_NODEPATH) - sizeof(struct ll_entry) + sizeof(uint64_t)) { + fail_path = 0; + DEBUG_WARN(DEBUG_CATEGORY_BGP, "[fault] reject incoming BGP path allocation"); return NULL; + } + return __real_queue_entry_new(size); +} +#endif + static struct TOPO_GROUP_CONN_ITEM* peer(struct TOPO_GROUP* group) { assert(group->senders_list->head && !group->senders_list->head->next); return (struct TOPO_GROUP_CONN_ITEM*)group->senders_list->head->data; @@ -140,6 +152,18 @@ int main(void) { assert(queue_entry_count(routed->paths) == 1 && topo_group_find_conn_for_node(a, node.node_id) == conn); assert(topo_group_process_withdraw(a, &relay, (const uint8_t*)&alternate_wd, sizeof(alternate_wd)) == 0); assert(topo_node_find_by_id(a, node.node_id) == routed && queue_entry_count(routed->paths) == 1); +#ifdef __linux__ + /* Поздний OOM не меняет подписанную запись, per-group поля и предыдущий путь. */ + struct ll_queue* previous_paths = routed->paths; + struct TOPO_NODE* previous_record = topo_node_registry_find(inst->topo_groups, node.node_id); + uint32_t previous_refs = previous_record->group_ref_count; + fail_path = 1; + nodeinfo(a, conn, &node, &keys, a_id, 2); + assert(!fail_path && peer(a)->tx_failed && !topo_group_peer_ready(a, node.node_id)); + assert(topo_node_find_by_id(a, node.node_id) == routed && routed->paths == previous_paths); + assert(routed->last_timestamp == 1 && previous_record->timestamp == 1 && previous_record->group_ref_count == previous_refs); + assert(queue_entry_count(routed->paths) == 1 && topo_group_find_conn_for_node(a, node.node_id) == conn); +#endif etcp_fire_conn_status(conn, ETCP_CONN_STATUS_REINIT); assert(topo_group_find_conn_for_node(a, node.node_id) == conn); /* REINIT preserves known paths */ assert(peer(a)->local_epoch != a_id && peer(b)->local_epoch != b_id);