From 0e9a91729c805af719cc0ea36d8769aed7731bb4 Mon Sep 17 00:00:00 2001 From: jeka Date: Sat, 7 Mar 2026 20:47:15 +0300 Subject: [PATCH] 1 --- doc/dgram_protocol.txt | 2 - doc/etcp_arch.md | 26 +++++++ lib/ll_queue.h | 1 + src/control_server.c | 22 ++++++ src/routing.c | 7 ++ src/utun_instance.h | 4 ++ tools/etcpmon/etcpmon_gui.c | 117 ++++++++++++++++++++++++++----- tools/etcpmon/etcpmon_gui.h | 22 ++++++ tools/etcpmon/etcpmon_protocol.h | 15 ++++ 9 files changed, 195 insertions(+), 21 deletions(-) delete mode 100644 doc/dgram_protocol.txt diff --git a/doc/dgram_protocol.txt b/doc/dgram_protocol.txt deleted file mode 100644 index 80b2e19..0000000 --- a/doc/dgram_protocol.txt +++ /dev/null @@ -1,2 +0,0 @@ -форматы кодограмм протокола dgram: -- dgram протокол отправляет сообщения в очередь input pkt_normalizer. diff --git a/doc/etcp_arch.md b/doc/etcp_arch.md index 0878095..729c27f 100644 --- a/doc/etcp_arch.md +++ b/doc/etcp_arch.md @@ -1,5 +1,31 @@ Архитектура etcp: +ETCP устанавливает только одно подключение между двумя узлами. Это подключение может добавлять-убирать каналы связи (динамически) без разрыва соединения. +Также каналы связи мониторятся и трафик распределяется между доступными каналами. Если канал определяется как недоступен - он исключается из обмена. +Все каналы периодически мониторятся на доступность (keepalive). + +Роутинг. +utun поддерживает встроенный ipv4 роутинг, может через промежуточные узлы доставлять пакеты. +У каждого узла есть свои маршруты. Эти маршруты при подключении распространяются по остальным узлам. +Связь между узлами: + Каждый узел имеет настройку NAT для каждого listen сокета: public / nat / private. + public - нет nat, можно подключаться напрямую + nat - есть правильный nat с static port (т.е. можно подключаться напрямую зная присвоенный ip:port) + private - нельзя подключаться + Приоритетный способ обмена данными - прямое подключение к узлу. Если один из узлов имеет не private интерфейс то создается подключение через него. + Если не удается подключиться напрямую - выбирается переадча через промежуточный узел с наилучшим качеством канала (считается из задержки, числа хопов, bandwidth, потерь) + Для установки прямого соединения шлётся запрос удаленному узлу через существующие соединения на запрос подключения. + Запрос включает мой id, pubkey, доступные каналы связи и их [ip:port]. удаленный узел запоминает эти данные и отправляет response с такими же данными. + При получении request или response узел смотрит каких подключений (links) еще нет и пробует инициировать на подходщих линках с узлом. + Таким образом будет инициировано подключение между узлами по всем доступным линкам. + Если у каждого из узлов есть более одного канала то создаётся m * n подключений (каждый сокет с каждым). которые дальше работают как обычно - балансировщик нагрузки далее в процессе выбирает как лучше отправить очередной пакет (больше вариантов - можно найти путь лучше). + Есть статические подключения (которые прописаны в конфиге) и есть динамические - которые устанавливаются в процессе по необходимости. + Обмен маршрутами происходит только через статические подключения. + +toto: + - задать ограничение bandwidth для каждого сокета (общее). + + ## etcp_connections: - обслуживает encrypt/decrypt и установку защищенного подключения. - для одного etcp соединения может испольоваться несколько подключений одновременно (load balancing / filover) diff --git a/lib/ll_queue.h b/lib/ll_queue.h index c8cc5a3..2c5b00f 100644 --- a/lib/ll_queue.h +++ b/lib/ll_queue.h @@ -6,6 +6,7 @@ #include "memory_pool.h" // для struct memory_pool #ifdef _WIN32 + #include #include #else #include diff --git a/src/control_server.c b/src/control_server.c index 2a4cad9..8ebc718 100644 --- a/src/control_server.c +++ b/src/control_server.c @@ -9,6 +9,7 @@ #include "etcp.h" #include "etcp_connections.h" #include "tun_if.h" +#include "route_lib.h" #include "../lib/u_async.h" #include "../lib/debug_config.h" #include "../lib/mem.h" @@ -767,6 +768,27 @@ static void send_metrics(struct control_server* server, struct control_client* c rsp->tun.packets_written = instance->tun->packets_written; rsp->tun.read_errors = instance->tun->read_errors; rsp->tun.write_errors = instance->tun->write_errors; + + /* Routing statistics */ + rsp->tun.routed_packets = instance->routed_packets; + rsp->tun.dropped_packets = instance->dropped_packets; + + /* TUN queues */ + rsp->tun.tun_in_q_packets = (uint32_t)queue_entry_count(instance->tun->input_queue); + rsp->tun.tun_in_q_bytes = (uint32_t)queue_total_bytes(instance->tun->input_queue); + rsp->tun.tun_out_q_packets = (uint32_t)queue_entry_count(instance->tun->output_queue); + rsp->tun.tun_out_q_bytes = (uint32_t)queue_total_bytes(instance->tun->output_queue); + + /* Routing table */ + if (instance->rt) { + rsp->tun.rt_count = (uint32_t)instance->rt->count; + rsp->tun.rt_local = (uint32_t)instance->rt->stats.local_routes; + rsp->tun.rt_learned = (uint32_t)instance->rt->stats.learned_routes; + } else { + rsp->tun.rt_count = 0; + rsp->tun.rt_local = 0; + rsp->tun.rt_learned = 0; + } } else { memset(&rsp->tun, 0, sizeof(rsp->tun)); } diff --git a/src/routing.c b/src/routing.c index cafecc3..d6adc46 100644 --- a/src/routing.c +++ b/src/routing.c @@ -114,6 +114,7 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) { struct ROUTE_ARRAY* routes = route_table_lookup(instance->rt, dst_ip); if (!routes || routes->routes == 0) { DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "route_pkt: no route to %s, dropping", ip_to_str(&addr, AF_INET).str); + instance->dropped_packets++; queue_entry_free(entry); queue_dgram_free(entry); return; @@ -124,11 +125,13 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) { // Local route - send to TUN (entry has [cmd=0][IP data], TUN skips cmd byte) if (queue_data_put(instance->tun->input_queue, entry, 0) != 0) { DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: failed to put to TUN input_queue"); + instance->dropped_packets++; queue_entry_free(entry); queue_dgram_free(entry); return; } // Entry sent to TUN, don't free here + instance->routed_packets++; DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "route_pkt: sent %zu bytes to TUN", ip_len); return; } @@ -137,6 +140,7 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) { struct ETCP_CONN* conn = routes->entries[0]->next_hop; if (!conn) { DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: route to %s has no next_hop, dropping", ip_to_str(&addr, AF_INET).str); + instance->dropped_packets++; queue_entry_free(entry); queue_dgram_free(entry); return; @@ -144,6 +148,7 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) { if (!conn->normalizer) { DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: connection for %s has no normalizer, dropping", ip_to_str(&addr, AF_INET).str); + instance->dropped_packets++; queue_entry_free(entry); queue_dgram_free(entry); return; @@ -153,12 +158,14 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) { DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "route_pkt: sending %zu bytes to ETCP %s", ip_len, conn->log_name); if (etcp_send(conn, entry) != 0) { DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: etcp_send failed for %s", ip_to_str(&addr, AF_INET).str); + instance->dropped_packets++; queue_entry_free(entry); queue_dgram_free(entry); return; } // Entry sent successfully, don't free here + instance->routed_packets++; } // Callback for packets from ETCP (via etcp_bind id=0) diff --git a/src/utun_instance.h b/src/utun_instance.h index 0ea3256..2f5d544 100644 --- a/src/utun_instance.h +++ b/src/utun_instance.h @@ -56,6 +56,10 @@ struct UTUN_INSTANCE { // Active sockets struct ETCP_SOCKET* etcp_sockets;// linked-list + // Routing statistics + uint64_t routed_packets; + uint64_t dropped_packets; + // ETCP API bindings (per-instance) struct ETCP_BINDINGS api_bindings; diff --git a/tools/etcpmon/etcpmon_gui.c b/tools/etcpmon/etcpmon_gui.c index b333f27..355cffe 100644 --- a/tools/etcpmon/etcpmon_gui.c +++ b/tools/etcpmon/etcpmon_gui.c @@ -19,7 +19,7 @@ //#pragma comment(lib, "user32.lib") //#pragma comment(lib, "gdi32.lib") #define WINDOW_WIDTH 900 -#define WINDOW_HEIGHT 1080 +#define WINDOW_HEIGHT 1150 #define UPDATE_INTERVAL 10 /* 50ms → 20 samples per second */ /* Global app pointer for callbacks */ static struct etcpmon_app* g_app = NULL; @@ -255,7 +255,7 @@ static void CreateControls(struct etcpmon_app* app) { y = 485; CreateWindowExA(0, "BUTTON", "ETCP Metrics", WS_CHILD | WS_VISIBLE | BS_GROUPBOX, - x, y, 430, 220, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + x, y, 430, 180, hWnd, (HMENU)IDC_STATIC, hInst, NULL); int mx = x + 10, my = y + 20; @@ -263,7 +263,7 @@ static void CreateControls(struct etcpmon_app* app) { WS_CHILD | WS_VISIBLE, mx, my, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); app->hEditEtcpName = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_AUTOHSCROLL, - mx + 85, my, 330, 20, hWnd, (HMENU)IDC_EDIT_ETCP_NAME, hInst, NULL); + mx + 85, my, 310, 20, hWnd, (HMENU)IDC_EDIT_ETCP_NAME, hInst, NULL); my += 25; CreateWindowExA(0, "STATIC", "RTT Last:", @@ -279,7 +279,7 @@ static void CreateControls(struct etcpmon_app* app) { mx + 285, my, 100, 20, hWnd, (HMENU)IDC_EDIT_ETCP_RTT_AVG10, hInst, NULL); my += 25; - CreateWindowExA(0, "STATIC", "RTT Avg 100:", + CreateWindowExA(0, "STATIC", "RTTAvg100:", WS_CHILD | WS_VISIBLE, mx, my, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); app->hEditEtcpRttAvg100 = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY, @@ -324,11 +324,11 @@ static void CreateControls(struct etcpmon_app* app) { WS_CHILD | WS_VISIBLE | ES_READONLY, mx + 85, my, 100, 20, hWnd, (HMENU)IDC_EDIT_ETCP_LINKS, hInst, NULL); - /* TUN Metrics group - right of ETCP Metrics */ + /* TUN/Routing Metrics group - right of ETCP Metrics */ x = 460; y = 485; - CreateWindowExA(0, "BUTTON", "TUN Metrics", + CreateWindowExA(0, "BUTTON", "TUN/Routing Metrics", WS_CHILD | WS_VISIBLE | BS_GROUPBOX, - x, y, 430, 140, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + x, y, 430, 180, hWnd, (HMENU)IDC_STATIC, hInst, NULL); mx = x + 10; my = y + 20; @@ -339,7 +339,7 @@ static void CreateControls(struct etcpmon_app* app) { mx + 85, my, 100, 20, hWnd, (HMENU)IDC_EDIT_TUN_READ_BYTES, hInst, NULL); CreateWindowExA(0, "STATIC", "Write Bytes:", - WS_CHILD | WS_VISIBLE, mx + 200, my, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + WS_CHILD | WS_VISIBLE, mx + 200, my, 90, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); app->hEditTunWriteBytes = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY, mx + 285, my, 100, 20, hWnd, (HMENU)IDC_EDIT_TUN_WRITE_BYTES, hInst, NULL); @@ -352,7 +352,7 @@ static void CreateControls(struct etcpmon_app* app) { mx + 85, my, 100, 20, hWnd, (HMENU)IDC_EDIT_TUN_READ_PKTS, hInst, NULL); CreateWindowExA(0, "STATIC", "Write Pkts:", - WS_CHILD | WS_VISIBLE, mx + 200, my, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + WS_CHILD | WS_VISIBLE, mx + 200, my, 90, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); app->hEditTunWritePkts = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY, mx + 285, my, 100, 20, hWnd, (HMENU)IDC_EDIT_TUN_WRITE_PKTS, hInst, NULL); @@ -365,11 +365,63 @@ static void CreateControls(struct etcpmon_app* app) { mx + 85, my, 100, 20, hWnd, (HMENU)IDC_EDIT_TUN_READ_ERRS, hInst, NULL); CreateWindowExA(0, "STATIC", "Write Errs:", - WS_CHILD | WS_VISIBLE, mx + 200, my, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + WS_CHILD | WS_VISIBLE, mx + 200, my, 90, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); app->hEditTunWriteErrs = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY, mx + 285, my, 100, 20, hWnd, (HMENU)IDC_EDIT_TUN_WRITE_ERRS, hInst, NULL); + /* Routing section */ + my += 30; + CreateWindowExA(0, "STATIC", "Routed:", + WS_CHILD | WS_VISIBLE, mx, my, 60, 18, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + app->hEditRtRouted = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, + mx + 65, my - 2, 80, 18, hWnd, (HMENU)IDC_EDIT_RT_ROUTED, hInst, NULL); + + CreateWindowExA(0, "STATIC", "Dropped:", + WS_CHILD | WS_VISIBLE, mx + 155, my, 60, 18, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + app->hEditRtDropped = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, + mx + 220, my - 2, 80, 18, hWnd, (HMENU)IDC_EDIT_RT_DROPPED, hInst, NULL); + + my += 25; + CreateWindowExA(0, "STATIC", "TunInQ:", + WS_CHILD | WS_VISIBLE, mx, my, 60, 18, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + app->hEditRtTunInQPkts = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, + mx + 65, my - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_RT_TUN_IN_Q_PKTS, hInst, NULL); + app->hEditRtTunInQBytes = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, + mx + 120, my - 2, 60, 18, hWnd, (HMENU)IDC_EDIT_RT_TUN_IN_Q_BYTES, hInst, NULL); + + CreateWindowExA(0, "STATIC", "TunOutQ:", + WS_CHILD | WS_VISIBLE, mx + 190, my, 60, 18, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + app->hEditRtTunOutQPkts = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, + mx + 255, my - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_RT_TUN_OUT_Q_PKTS, hInst, NULL); + app->hEditRtTunOutQBytes = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, + mx + 310, my - 2, 60, 18, hWnd, (HMENU)IDC_EDIT_RT_TUN_OUT_Q_BYTES, hInst, NULL); + + my += 25; + CreateWindowExA(0, "STATIC", "RT:", + WS_CHILD | WS_VISIBLE, mx, my, 30, 18, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + app->hEditRtCount = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, + mx + 35, my - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_RT_COUNT, hInst, NULL); + + CreateWindowExA(0, "STATIC", "Local:", + WS_CHILD | WS_VISIBLE, mx + 95, my, 40, 18, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + app->hEditRtLocal = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, + mx + 140, my - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_RT_LOCAL, hInst, NULL); + + CreateWindowExA(0, "STATIC", "Learned:", + WS_CHILD | WS_VISIBLE, mx + 200, my, 55, 18, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + app->hEditRtLearned = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, + mx + 260, my - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_RT_LEARNED, hInst, NULL); + /* Links list */ y = 715; CreateWindowExA(0, "STATIC", "Links:", @@ -378,10 +430,10 @@ static void CreateControls(struct etcpmon_app* app) { app->hListLinks = CreateWindowExA(WS_EX_CLIENTEDGE, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT, - 10, y + 20, 880, 100, hWnd, (HMENU)IDC_LIST_LINKS, hInst, NULL); + 10, y + 20, 880, 160, hWnd, (HMENU)IDC_LIST_LINKS, hInst, NULL); /* Queues & Errors group - below Links */ - y = 845; + y = 905; CreateWindowExA(0, "BUTTON", "Queues & Errors", WS_CHILD | WS_VISIBLE | BS_GROUPBOX, 10, y, 880, 165, hWnd, (HMENU)IDC_STATIC_QUEUES, hInst, NULL); @@ -765,6 +817,17 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app, UpdateEditIfChanged(hMain, IDC_EDIT_TUN_READ_ERRS, "%u", metrics->tun.read_errors); UpdateEditIfChanged(hMain, IDC_EDIT_TUN_WRITE_ERRS, "%u", metrics->tun.write_errors); + /* Routing Metrics */ + UpdateEditIfChanged(hMain, IDC_EDIT_RT_ROUTED, "%llu", (unsigned long long)metrics->tun.routed_packets); + UpdateEditIfChanged(hMain, IDC_EDIT_RT_DROPPED, "%llu", (unsigned long long)metrics->tun.dropped_packets); + UpdateEditIfChanged(hMain, IDC_EDIT_RT_TUN_IN_Q_PKTS, "%u", metrics->tun.tun_in_q_packets); + UpdateEditIfChanged(hMain, IDC_EDIT_RT_TUN_IN_Q_BYTES, "%u", metrics->tun.tun_in_q_bytes); + UpdateEditIfChanged(hMain, IDC_EDIT_RT_TUN_OUT_Q_PKTS, "%u", metrics->tun.tun_out_q_packets); + UpdateEditIfChanged(hMain, IDC_EDIT_RT_TUN_OUT_Q_BYTES, "%u", metrics->tun.tun_out_q_bytes); + UpdateEditIfChanged(hMain, IDC_EDIT_RT_COUNT, "%u", metrics->tun.rt_count); + UpdateEditIfChanged(hMain, IDC_EDIT_RT_LOCAL, "%u", metrics->tun.rt_local); + UpdateEditIfChanged(hMain, IDC_EDIT_RT_LEARNED, "%u", metrics->tun.rt_learned); + /* Queue Metrics */ UpdateEditIfChanged(hMain, IDC_EDIT_Q_IN_Q_BYTES, "%u", metrics->etcp.input_queue_bytes); UpdateEditIfChanged(hMain, IDC_EDIT_Q_IN_Q_PKTS, "%u", metrics->etcp.input_queue_packets); @@ -798,13 +861,13 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app, if (app->hListLinks) { SendMessage(app->hListLinks, LB_RESETCONTENT, 0, 0); for (uint8_t i = 0; i < links_count; i++) { - char display[380]; - snprintf(display, sizeof(display), + char line1[320]; + char line2[256]; + + snprintf(line1, sizeof(line1), "Link %u: Status=%s, EncErr=%u, DecErr=%u, " "SndErr=%u, RcvErr=%u, Enc=%llu, Dec=%llu, " - "BW=%u Kbps, NAT=%u, RTT=%u us, TT=%u us, " - "Timers: Init=%s, KA=%s, Shaper=%s, " - "KAsent=%u, KArecv=%u", + "BW=%u Kbps, NAT=%u, RTT=%u us, TT=%u us", links[i].local_link_id, links[i].status ? "UP" : "DOWN", links[i].encrypt_errors, @@ -816,13 +879,19 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app, links[i].bandwidth, links[i].nat_changes_count, links[i].rtt_last * 100, - links[i].tt_last * 100, + links[i].tt_last * 100); + + snprintf(line2, sizeof(line2), + " Timers: Init=%s, KA=%s, Shaper=%s | " + "KAsent=%u, KArecv=%u", links[i].init_timer_active ? "ON" : "OFF", links[i].keepalive_timer_active ? "ON" : "OFF", links[i].shaper_timer_active ? "ON" : "OFF", links[i].keepalive_sent, links[i].keepalive_recv); - SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)display); + + SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)line1); + SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)line2); } InvalidateRect(app->hListLinks, NULL, FALSE); } @@ -851,6 +920,16 @@ void etcpmon_gui_clear_metrics(struct etcpmon_app* app) { SetDlgItemTextA(app->hWndMain, IDC_EDIT_TUN_READ_ERRS, ""); SetDlgItemTextA(app->hWndMain, IDC_EDIT_TUN_WRITE_ERRS, ""); + SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_ROUTED, ""); + SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_DROPPED, ""); + SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_TUN_IN_Q_PKTS, ""); + SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_TUN_IN_Q_BYTES, ""); + SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_TUN_OUT_Q_PKTS, ""); + SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_TUN_OUT_Q_BYTES, ""); + SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_COUNT, ""); + SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_LOCAL, ""); + SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_LEARNED, ""); + SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_IN_Q_BYTES, ""); SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_IN_Q_PKTS, ""); SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_IN_SEND_BYTES, ""); diff --git a/tools/etcpmon/etcpmon_gui.h b/tools/etcpmon/etcpmon_gui.h index 0b289d5..3fa0caa 100644 --- a/tools/etcpmon/etcpmon_gui.h +++ b/tools/etcpmon/etcpmon_gui.h @@ -59,6 +59,17 @@ extern "C" { #define IDC_EDIT_TUN_READ_ERRS 304 #define IDC_EDIT_TUN_WRITE_ERRS 305 +/* Routing Metrics control IDs */ +#define IDC_EDIT_RT_ROUTED 306 +#define IDC_EDIT_RT_DROPPED 307 +#define IDC_EDIT_RT_TUN_IN_Q_PKTS 308 +#define IDC_EDIT_RT_TUN_IN_Q_BYTES 309 +#define IDC_EDIT_RT_TUN_OUT_Q_PKTS 310 +#define IDC_EDIT_RT_TUN_OUT_Q_BYTES 311 +#define IDC_EDIT_RT_COUNT 312 +#define IDC_EDIT_RT_LOCAL 313 +#define IDC_EDIT_RT_LEARNED 314 + /* Link list control ID */ #define IDC_LIST_LINKS 400 @@ -157,6 +168,17 @@ struct etcpmon_app { HWND hEditTunReadErrs; HWND hEditTunWriteErrs; + /* Routing metrics controls */ + HWND hEditRtRouted; + HWND hEditRtDropped; + HWND hEditRtTunInQPkts; + HWND hEditRtTunInQBytes; + HWND hEditRtTunOutQPkts; + HWND hEditRtTunOutQBytes; + HWND hEditRtCount; + HWND hEditRtLocal; + HWND hEditRtLearned; + /* Links list */ HWND hListLinks; diff --git a/tools/etcpmon/etcpmon_protocol.h b/tools/etcpmon/etcpmon_protocol.h index 0054ed6..c71a141 100644 --- a/tools/etcpmon/etcpmon_protocol.h +++ b/tools/etcpmon/etcpmon_protocol.h @@ -170,6 +170,21 @@ struct etcpmon_tun_metrics { uint32_t packets_written; /* Packets written to TUN */ uint32_t read_errors; /* Read error count */ uint32_t write_errors; /* Write error count */ + + /* Routing statistics */ + uint64_t routed_packets; /* Successfully routed packets */ + uint64_t dropped_packets; /* Dropped packets */ + + /* TUN queues */ + uint32_t tun_in_q_packets; /* Packets in TUN input queue */ + uint32_t tun_in_q_bytes; /* Bytes in TUN input queue */ + uint32_t tun_out_q_packets; /* Packets in TUN output queue */ + uint32_t tun_out_q_bytes; /* Bytes in TUN output queue */ + + /* Routing table */ + uint32_t rt_count; /* Total routes in table */ + uint32_t rt_local; /* Local routes */ + uint32_t rt_learned; /* Learned routes (BGP) */ }; struct etcpmon_rsp_metrics {