|
|
|
|
@ -26,6 +26,7 @@
|
|
|
|
|
#include <sys/stat.h> |
|
|
|
|
#include "../lib/platform_compat.h" |
|
|
|
|
#include "test_utils.h" |
|
|
|
|
#include "test_clock.h" |
|
|
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
#include <windows.h> |
|
|
|
|
@ -66,6 +67,18 @@ static void* timeout_id = NULL;
|
|
|
|
|
|
|
|
|
|
// dummynet filters per link
|
|
|
|
|
static struct test_connection_loss loss_ab, loss_bc; |
|
|
|
|
static int single_link_down, single_link_up; |
|
|
|
|
|
|
|
|
|
static void single_link_status(struct ETCP_CONN* conn, struct ETCP_LINK* link, int old_state, int old_status, void* arg) { |
|
|
|
|
(void)conn; (void)old_state; |
|
|
|
|
if (link != arg || old_status == link->link_status) return; |
|
|
|
|
if (link->link_status) single_link_up = 1; |
|
|
|
|
else single_link_down = 1; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "BGP single-link test: link=%u old_status=%d status=%d down=%d up=%d", |
|
|
|
|
link->local_link_id, old_status, link->link_status, single_link_down, single_link_up); |
|
|
|
|
} |
|
|
|
|
static int cond_single_link_down(void) { return single_link_down; } |
|
|
|
|
static int cond_single_link_up(void) { return single_link_up; } |
|
|
|
|
|
|
|
|
|
static char temp_dir[] = "/tmp/utun_bgp_mesh_XXXXXX"; |
|
|
|
|
static char config_a[256], config_b[256], config_c[256]; |
|
|
|
|
@ -259,7 +272,7 @@ static void fail(const char* msg) {
|
|
|
|
|
static int wait_for(const char* desc, int (*cond)(void), int timeout_tb) { |
|
|
|
|
uint64_t start = get_time_tb(); |
|
|
|
|
while (!cond() && (get_time_tb() - start) < (uint64_t)timeout_tb && test_phase == 0) |
|
|
|
|
uasync_poll(ua, POLL_INTERVAL_MS); |
|
|
|
|
test_clock_poll(ua, POLL_INTERVAL_MS); |
|
|
|
|
if (!cond() && test_phase == 0) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "timeout waiting for: %s", desc); |
|
|
|
|
test_phase = 2; |
|
|
|
|
@ -293,6 +306,7 @@ int main(void) {
|
|
|
|
|
debug_config_init(); |
|
|
|
|
debug_set_level(DEBUG_LEVEL_ERROR); |
|
|
|
|
debug_set_categories(DEBUG_CATEGORY_BGP); |
|
|
|
|
test_clock_init(1000); |
|
|
|
|
if (getenv("UTUN_TEST_DEBUG")) { |
|
|
|
|
debug_set_category_level(DEBUG_CATEGORY_BGP, DEBUG_LEVEL_DEBUG); |
|
|
|
|
debug_set_category_level(DEBUG_CATEGORY_ETCP, DEBUG_LEVEL_DEBUG); |
|
|
|
|
@ -348,17 +362,19 @@ int main(void) {
|
|
|
|
|
|
|
|
|
|
// --- Phase 2: Kill one A↔B link, verify routes stay ---
|
|
|
|
|
PHASE("2: Kill one A↔B link"); |
|
|
|
|
etcp_add_link_status_cbk(inst_a, single_link_status, ab_link1); |
|
|
|
|
test_loss_set(&loss_ab, 1, ab_link1, NULL); |
|
|
|
|
// Wait for link-down detection by keepalive, then verify routes survive (link2 still up)
|
|
|
|
|
for (int i = 0; i < 200 && test_phase == 0 && ab_link1->link_status; i++) uasync_poll(ua, POLL_INTERVAL_MS); |
|
|
|
|
// Small margin after link-down before checks
|
|
|
|
|
for (int i = 0; i < 40 && test_phase == 0; i++) uasync_poll(ua, POLL_INTERVAL_MS); |
|
|
|
|
// Маршрут должен пережить подтверждённый DOWN одного линка.
|
|
|
|
|
ASSERT(wait_for("single A-B link DOWN", cond_single_link_down, PHASE_TIMEOUT_TB), "single link did not go DOWN"); |
|
|
|
|
test_clock_run_for(ua, 400); // Сохраняем 40мс проверки стабильности после DOWN.
|
|
|
|
|
ASSERT(check_learned_route(inst_a, ntohl(inet_addr("192.168.30.0")), 24, g_node_id_c), "routes lost after 1 link down"); |
|
|
|
|
ASSERT(check_learned_route(inst_c, ntohl(inet_addr("192.168.10.0")), 24, g_node_id_a), "routes lost C side"); |
|
|
|
|
|
|
|
|
|
// --- Phase 3: Restore the link ---
|
|
|
|
|
PHASE("3: Restore one A↔B link"); |
|
|
|
|
test_loss_set(&loss_ab, 0, NULL, NULL); |
|
|
|
|
ASSERT(wait_for("single A-B link UP", cond_single_link_up, PHASE_TIMEOUT_TB), "single link did not restore UP"); |
|
|
|
|
etcp_remove_link_status_cbk(inst_a, single_link_status, ab_link1); |
|
|
|
|
ASSERT(wait_for("BGP recovery after ab1 restored", cond_bgp_a_to_c, PHASE_TIMEOUT_TB), "bgp A→C recovery"); |
|
|
|
|
|
|
|
|
|
// --- Phase 4: Kill B↔C link ---
|
|
|
|
|
@ -397,6 +413,7 @@ int main(void) {
|
|
|
|
|
if (ua) { uasync_poll(ua, 0); uasync_destroy(ua, 0); ua = NULL; } |
|
|
|
|
cleanup_temp_configs(); |
|
|
|
|
|
|
|
|
|
test_clock_finish(); |
|
|
|
|
printf("=== %s ===\n", test_phase == 1 ? "TEST PASSED" : "TEST FAILED"); |
|
|
|
|
return test_phase == 1 ? 0 : 1; |
|
|
|
|
} |
|
|
|
|
|