Trace radio mesh packet paths and original stop conditions
This commit is contained in:
1 parent
5587c60603
commit
c2908a6c58
2 files changed
+89
No files matched your search
@@ -955,6 +955,10 @@ test_radio_headless_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
test_radio_mesh_SOURCES = test_radio_mesh.c
|
||||
test_radio_mesh_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/chat -I$(top_srcdir)/src/dm -I$(top_srcdir)/src/call -I$(top_srcdir)/src/radio -I$(top_srcdir)/src/routing_layer -I$(top_srcdir)/src/transport_layer -I$(top_srcdir)/lib
|
||||
test_radio_mesh_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
if !OS_WINDOWS
|
||||
test_radio_mesh_CFLAGS += -DUTUN_TEST_MESH_OBSERVE
|
||||
test_radio_mesh_LDFLAGS = -Wl,--wrap=etcp_bind -Wl,--wrap=etcp_send
|
||||
endif
|
||||
|
||||
test_stcp_traffic_SOURCES = test_stcp_traffic.c
|
||||
test_stcp_traffic_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "chat_event.h"
|
||||
#include "member_sync.h"
|
||||
#include "../radio/radio.h"
|
||||
#include "../radio/radio_proto.h"
|
||||
#include "../routing_layer/topo_node_sqlite.h"
|
||||
#include "../routing_layer/topo_group.h"
|
||||
#include "../routing_layer/topo_node.h"
|
||||
@@ -90,6 +91,76 @@ struct mesh_shared {
|
||||
};
|
||||
static struct mesh_shared g_sh;
|
||||
static struct rx_evt g_rx[4];
|
||||
static const char* g_names[4] = {"A", "B", "D", "C"};
|
||||
|
||||
static int mesh_node_index(uint64_t id) {
|
||||
for (int i = 0; i < 4; ++i) if (g_sh.nid[i] == id) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef UTUN_TEST_MESH_OBSERVE
|
||||
/* Наблюдаем raw ETCP до дедупликации, не меняя данные/результат или владение entry. */
|
||||
static etcp_recv_fn g_radio_recv;
|
||||
static unsigned int g_wire_tx[4][4], g_wire_rx[4][4];
|
||||
extern int __real_etcp_bind(struct UTUN_INSTANCE* inst, uint8_t id, etcp_recv_fn callback);
|
||||
extern int __real_etcp_send(struct ETCP_CONN* conn, struct ll_entry* entry);
|
||||
|
||||
static void mesh_wire(const char* direction, struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
if (!conn || !entry || entry->len < 1 + RADIO_HDR_SIZE || entry->dgram[0] != ETCP_ID_RADIO) return;
|
||||
const uint8_t* p = entry->dgram + 1;
|
||||
uint64_t group, src; uint16_t stream, seq;
|
||||
memcpy(&group, p + RADIO_OFF_GROUP, 8); memcpy(&src, p + RADIO_OFF_SRC, 8);
|
||||
memcpy(&stream, p + RADIO_OFF_STREAM, 2); memcpy(&seq, p + RADIO_OFF_SEQ, 2);
|
||||
int self = mesh_node_index(conn->instance->node_id), peer = mesh_node_index(conn->peer_node_id);
|
||||
if (self >= 0 && peer >= 0) {
|
||||
if (!strcmp(direction, "TX")) ++g_wire_tx[self][peer]; else ++g_wire_rx[self][peer];
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG,
|
||||
"mesh wire %s self=%s peer=%s group=%016llx src=%016llx stream=%u seq=%u fin=%d hops=%u",
|
||||
direction, self < 0 ? "?" : g_names[self], peer < 0 ? "?" : g_names[peer],
|
||||
(unsigned long long)group, (unsigned long long)src, stream, seq, !!(p[RADIO_OFF_FLAGS] & RADIO_FLAG_FIN),
|
||||
p[RADIO_OFF_HOPS]);
|
||||
}
|
||||
|
||||
static void mesh_radio_recv(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
mesh_wire("RX", conn, entry);
|
||||
g_radio_recv(conn, entry);
|
||||
}
|
||||
|
||||
int __wrap_etcp_bind(struct UTUN_INSTANCE* inst, uint8_t id, etcp_recv_fn callback) {
|
||||
if (id == ETCP_ID_RADIO) {
|
||||
if (g_radio_recv && g_radio_recv != callback) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "mesh: unexpected different radio callback"); abort();
|
||||
}
|
||||
g_radio_recv = callback;
|
||||
return __real_etcp_bind(inst, id, mesh_radio_recv);
|
||||
}
|
||||
return __real_etcp_bind(inst, id, callback);
|
||||
}
|
||||
|
||||
int __wrap_etcp_send(struct ETCP_CONN* conn, struct ll_entry* entry) {
|
||||
mesh_wire("TX", conn, entry);
|
||||
return __real_etcp_send(conn, entry);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void mesh_snapshot(struct mesh_ctx* t, const char* reason) {
|
||||
uint64_t gid = strtoull(CH_ID, NULL, 10);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "mesh snapshot reason=%s phase=%d tick=%d tb=%llu", reason, t->phase, t->ticks,
|
||||
(unsigned long long)get_time_tb());
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "mesh node=%s id=%016llx frames=%d fin=%d seq_ok=%d next_seq=%u dup=%u",
|
||||
g_names[i], (unsigned long long)g_sh.nid[i], g_rx[i].frames, g_rx[i].fin_seen,
|
||||
g_rx[i].seq_ok, g_rx[i].expect_seq, radio_dup_dropped(t->inst[i], gid));
|
||||
#ifdef UTUN_TEST_MESH_OBSERVE
|
||||
for (int j = 0; j < 4; ++j) if (g_wire_tx[i][j] || g_wire_rx[i][j])
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "mesh edge self=%s peer=%s tx=%u rx=%u",
|
||||
g_names[i], g_names[j], g_wire_tx[i][j], g_wire_rx[i][j]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void mesh_tail_stop(void* arg) { uasync_stop(arg); }
|
||||
|
||||
static int G_PASSED = 0, G_FAILED = 0, G_TOTAL = 0;
|
||||
#define TEST(n) do { G_TOTAL++; printf(" %-58s", n); fflush(stdout); } while(0)
|
||||
@@ -345,6 +416,7 @@ static void mesh_tick(void* arg) {
|
||||
struct UTUN_INSTANCE* D = t->inst[IDX_D];
|
||||
struct UTUN_INSTANCE* C = t->inst[IDX_C];
|
||||
uint64_t gid = strtoull(CH_ID, NULL, 10);
|
||||
enum mesh_phase previous = t->phase;
|
||||
|
||||
switch (t->phase) {
|
||||
case P_WAIT_CONN:
|
||||
@@ -383,11 +455,14 @@ static void mesh_tick(void* arg) {
|
||||
t->phase = P_DONE;
|
||||
break;
|
||||
case P_DONE:
|
||||
mesh_snapshot(t, "original_stop");
|
||||
t->result = 1;
|
||||
uasync_stop(t->ua);
|
||||
return;
|
||||
}
|
||||
|
||||
if (previous != t->phase) mesh_snapshot(t, "phase_change");
|
||||
|
||||
if (++t->ticks > MAX_TICKS) {
|
||||
fprintf(stderr, "test: timeout in phase %d (B_rx=%d/%d fin=%d seqok=%d D_rx=%d/%d fin=%d seqok=%d C_rx=%d/%d fin=%d seqok=%d dupC=%u)\n",
|
||||
(int)t->phase,
|
||||
@@ -407,6 +482,7 @@ static void mesh_tick(void* arg) {
|
||||
int main(int argc, char** argv) {
|
||||
(void)argc; (void)argv;
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR);
|
||||
debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_INFO);
|
||||
if (getenv("UTUN_TEST_DEBUG")) {
|
||||
debug_set_category_level_by_name("radio", "debug");
|
||||
debug_set_category_level_by_name("bgp", "info");
|
||||
@@ -457,6 +533,15 @@ int main(int argc, char** argv) {
|
||||
uint64_t gid = strtoull(CH_ID, NULL, 10);
|
||||
uint32_t dup_c = radio_dup_dropped(t.inst[IDX_C], gid);
|
||||
|
||||
/* Диагностический хвост не меняет сохранённый результат исходной проверки. */
|
||||
if (getenv("UTUN_TEST_MESH_TAIL")) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "mesh observe tail=500ms original_ok=%d original_dupC=%u", ok, dup_c);
|
||||
void* tail = uasync_set_timeout(ua, 5000, ua, mesh_tail_stop, "mesh_diagnostic_tail");
|
||||
if (!tail) { DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "mesh: tail timer allocation failed"); abort(); }
|
||||
uasync_mainloop(ua);
|
||||
mesh_snapshot(&t, "after_diagnostic_tail");
|
||||
}
|
||||
|
||||
if (ok && dup_c == 0) {
|
||||
/* кадры не задвоились, но и дедупликация не сработала — топология не дала дублей */
|
||||
printf("WARN: dupC=0 — diamond не породил дублей, кэш не проверен\n");
|
||||
|
||||
Reference in new issue
Block a user