Exercise group creation rollback radio retry and BGP subnets
This commit is contained in:
1 parent
4363a424d0
commit
6b413d67a6
2 files changed
+63
-1
No files matched your search
@@ -10,6 +10,7 @@
|
||||
#include "etcp_api.h"
|
||||
#include "etcp_router.h"
|
||||
#include "route_crypto.h"
|
||||
#include "route_lib.h"
|
||||
#include "node_conn_direct.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "test_utils.h"
|
||||
@@ -183,6 +184,30 @@ static void metric_jitter(void) {
|
||||
assert(delivered == before); /* RTT is telemetry, not routing state. */
|
||||
}
|
||||
|
||||
/* Новый набор подсетей обязан заменять старый на всех узлах, включая пустой набор. */
|
||||
static void subnet_replacement(void) {
|
||||
struct CFG_ROUTE_ENTRY subnet = {.ip.family = AF_INET, .netmask = 24};
|
||||
for (int phase = 0; phase < 3; phase++) {
|
||||
subnet.ip.addr.v4.s_addr = htonl(phase == 0 ? 0x0a630000 : 0x0a640000);
|
||||
nodes[0]->config->my_subnets = phase < 2 ? &subnet : NULL;
|
||||
assert(topo_group_update_my_nodeinfo(nodes[0], groups[0]) == (phase < 2));
|
||||
nodes[0]->config->my_subnets = NULL;
|
||||
for (struct ll_entry* e = groups[0]->senders_list->head; e; e = e->next) {
|
||||
struct TOPO_GROUP_CONN_ITEM* p = (struct TOPO_GROUP_CONN_ITEM*)e->data;
|
||||
assert(topo_group_send_nodeinfo(groups[0], groups[0]->local_node, p->conn) == 0);
|
||||
}
|
||||
settle(); verify();
|
||||
for (int i = 0; i < N; i++) {
|
||||
struct ROUTE_ENTRY* old = route_lookup(nodes[i]->rt, 0x0a630001);
|
||||
struct ROUTE_ENTRY* current = route_lookup(nodes[i]->rt, 0x0a640001);
|
||||
assert((old != NULL) == (phase == 0) && (current != NULL) == (phase == 1));
|
||||
if (old) assert(old->v_node_info->node_id == nodes[0]->node_id);
|
||||
if (current) assert(current->v_node_info->node_id == nodes[0]->node_id);
|
||||
}
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP IPv4 subnet replacement and removal passed on all four nodes");
|
||||
}
|
||||
|
||||
static void service_receive(struct ETCP_CONN* conn, struct ll_entry* e) {
|
||||
if (e->len > ROUTER_SVC_HDR_SIZE) {
|
||||
assert(conn->instance == nodes[3]);
|
||||
@@ -336,6 +361,7 @@ int main(void) {
|
||||
create();
|
||||
unsigned triangle = edge(0, 1) | edge(1, 2) | edge(0, 2) | edge(2, 3);
|
||||
change(triangle); settle(); verify();
|
||||
subnet_replacement();
|
||||
metric_jitter();
|
||||
/* One-sided REINIT with routes retained, then simultaneous REINIT at all peers. */
|
||||
etcp_fire_conn_status(conns[0][1], ETCP_CONN_STATUS_REINIT); settle(); verify();
|
||||
|
||||
@@ -27,9 +27,12 @@ struct wire_fixture {
|
||||
#ifdef __linux__
|
||||
static unsigned fail_at, attempts, inside_pool;
|
||||
static int track_allocations;
|
||||
static int lifecycle_faults;
|
||||
|
||||
static int allocation_fails(const char *where) {
|
||||
if (!track_allocations || (!strstr(where, "topo_node.c:") && !strstr(where, "topo_node_sqlite.c:"))) return 0;
|
||||
if (!track_allocations || (!strstr(where, "topo_node.c:") && !strstr(where, "topo_node_sqlite.c:") &&
|
||||
!(lifecycle_faults && (strstr(where, "topo_group.c:") || strstr(where, "conn_mgr_core.c:") ||
|
||||
strstr(where, "broadcast.c:") || strstr(where, "radio.c:"))))) return 0;
|
||||
attempts++;
|
||||
if (attempts != fail_at) return 0;
|
||||
DEBUG_WARN(DEBUG_CATEGORY_BGP, "[fault] NODEINFO allocation %u rejected at %s", attempts, where);
|
||||
@@ -338,6 +341,39 @@ static void test_local_allocation_failures(struct wire_fixture *f) {
|
||||
assert(route_lookup(f->inst.rt, 0x0a020001)->v_node_info == old && !route_lookup(f->inst.rt, 0x0a030001));
|
||||
}
|
||||
fail_at = 0;
|
||||
/* Ошибка публикации radio не должна делать следующую такую же команду no-op. */
|
||||
struct TOPO_GROUP chat = {.instance = &f->inst, .group_id = 44, .group_type = TOPO_GROUP_TYPE_CHAT};
|
||||
assert(topo_group_update_my_nodeinfo(&f->inst, &chat) == 0);
|
||||
struct TOPO_GROUP_NODE* radio_before = chat.local_node;
|
||||
attempts = 0; fail_at = 1; track_allocations = 1;
|
||||
topo_group_set_radio(&chat, 1);
|
||||
track_allocations = 0; fail_at = 0;
|
||||
assert(!chat.radio_active && chat.local_node == radio_before && !chat.local_node->radio);
|
||||
topo_group_set_radio(&chat, 1);
|
||||
assert(chat.radio_active && chat.local_node->radio);
|
||||
topo_nodeq_free_group_fields(&f->groups, chat.local_node); u_free(chat.local_node);
|
||||
|
||||
/* Ни local_node, ни один из обязательных контекстов не может отсутствовать у возвращённой группы. */
|
||||
f->groups.group_list = queue_new(f->inst.ua, 16, 0, 8, "creation_faults"); assert(f->groups.group_list);
|
||||
attempts = 0; lifecycle_faults = 1; track_allocations = 1;
|
||||
struct TOPO_GROUP* created = topo_groups_create_group(&f->groups, 43, TOPO_GROUP_TYPE_UTUN, NULL);
|
||||
track_allocations = 0;
|
||||
assert(created && created->local_node && created->conn_mgr && created->broadcast && created->radio);
|
||||
unsigned creation_allocations = attempts;
|
||||
topo_groups_remove_group(&f->groups, 43); uasync_poll(f->inst.ua, 0);
|
||||
for (unsigned nth = 1; nth <= creation_allocations; nth++) {
|
||||
size_t before = live_allocations(), routes = f->inst.rt->count;
|
||||
uint32_t before_refs = node->group_ref_count;
|
||||
attempts = 0; fail_at = nth; track_allocations = 1;
|
||||
created = topo_groups_create_group(&f->groups, 43, TOPO_GROUP_TYPE_UTUN, NULL);
|
||||
track_allocations = 0; uasync_poll(f->inst.ua, 0);
|
||||
assert(!created && !topo_groups_find(&f->groups, 43));
|
||||
assert(node->group_ref_count == before_refs && f->inst.rt->count == routes && live_allocations() == before);
|
||||
}
|
||||
lifecycle_faults = 0; fail_at = 0;
|
||||
queue_free(f->groups.group_list); f->groups.group_list = NULL;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "[PASS] group creation: %u allocation failures roll back all resources; radio retry preserved",
|
||||
creation_allocations);
|
||||
topo_nodeq_free_group_fields(&f->groups, old); u_free(old); f->group.local_node = NULL;
|
||||
topo_node_registry_unref(&f->groups, f->inst.node_id);
|
||||
assert(!f->groups.node_registry->head); queue_free(f->groups.node_registry); f->groups.node_registry = NULL;
|
||||
|
||||
Reference in new issue
Block a user