Browse Source

etcp_router: add congestion counters, fix tx_seq rollback on etcp_send failure, add router metrics to etcpmon GUI

- etcp_router.h: add 9 per-conn counters (pkts_sent/err/rcvd, ack_sent/recv/stale, dup/oob/sign_fail)
- etcp_router.c: increment counters at 13 event points; fix tx_seq rollback on etcp_send failure (was causing phantom inflight=256 deadlock); add DEBUG_ERROR on all 5 ignored etcp_send returns; fix router_ack_do_send to update timestamps only on success
- etcpmon_protocol.h: add etcpmon_router_metrics (14 aggregated fields)
- control_server.c: iterate router_conns to fill aggregated router metrics
- etcpmon_gui: new 'Router Congestion' block with queue depths and all counters, Debug Levels shifted down, window 1300->1440
- test_etcp_router_unit: fix test_ack_timer for correct no-BGP-route behavior
chatgui
Evgeny 3 months ago
parent
commit
7329fa65f1
  1. 24
      src/control_server.c
  2. 78
      src/etcp_router.c
  3. 10
      src/etcp_router.h
  4. 8
      tests/test_etcp_router_unit.c
  5. 79
      tools/etcpmon/etcpmon_gui.c
  6. 31
      tools/etcpmon/etcpmon_gui.h
  7. 22
      tools/etcpmon/etcpmon_protocol.h

24
src/control_server.c

@ -11,6 +11,7 @@
#include "tun_if.h"
#include "route_lib.h"
#include "route_bgp.h"
#include "etcp_router.h"
#include "route_node.h"
#include "pkt_normalizer.h"
#include "../tools/etcpmon/etcpmon_protocol.h"
@ -1171,6 +1172,29 @@ static void send_metrics(struct control_server* server, struct control_client* c
memset(&rsp->tun, 0, sizeof(rsp->tun));
}
/* Fill router congestion metrics — aggregate over all router_conns */
memset(&rsp->router, 0, sizeof(rsp->router));
if (instance->router_conns) {
struct ll_entry* re;
while ((re = queue_data_get(instance->router_conns)) != NULL) {
struct ETCP_ROUTER_CONN* rc = (struct ETCP_ROUTER_CONN*)re;
rsp->router.total_inflight += (uint32_t)(rc->tx_seq - rc->tx_acked);
if (rc->send_q) rsp->router.total_send_q += (uint32_t)queue_entry_count(rc->send_q);
if (rc->recv_q) rsp->router.total_recv_q += (uint32_t)queue_entry_count(rc->recv_q);
rsp->router.pkts_sent += rc->c_pkts_sent;
rsp->router.pkts_send_err += rc->c_pkts_send_err;
rsp->router.pkts_rcvd += rc->c_pkts_rcvd;
rsp->router.ack_sent += rc->c_ack_sent;
rsp->router.ack_recv += rc->c_ack_recv;
rsp->router.dup_dropped += rc->c_dup_dropped;
rsp->router.oob_dropped += rc->c_oob_dropped;
rsp->router.stale_ack += rc->c_stale_ack;
rsp->router.sign_fail += rc->c_sign_fail;
queue_data_put_with_index(instance->router_conns, re);
}
rsp->router.total_conns = (uint32_t)queue_entry_count(instance->router_conns);
}
/* Fill link metrics */
struct etcpmon_link_metrics* link_info = (struct etcpmon_link_metrics*)(buffer + sizeof(*hdr) + sizeof(*rsp));
link = conn->links;

78
src/etcp_router.c

@ -58,7 +58,7 @@ static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t*
size_t sig_len = is_signed ? SC_SIGN_SIZE : 0;
size_t total_len = SVC_ROUTE_HDR_SIZE + pl_len + sig_len;
uint8_t* dgram = u_malloc(total_len);
if (!dgram) { if (!seq_flags) rconn->tx_seq--; return -1; }
if (!dgram) { if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; }
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)dgram;
hdr->cmd = ETCP_ID_SVC_ROUTE;
hdr->dst_node_id = rconn->remote_node_id;
@ -91,29 +91,29 @@ static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t*
if (!conn) {
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_send_one: no route to %016llx svc_id=%u",
(unsigned long long)rconn->remote_node_id, rconn->svc_id);
u_free(dgram); if (!seq_flags) rconn->tx_seq--; return -1;
u_free(dgram); if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1;
}
if (is_signed) {
struct sc_stream_sign_state sign_state;
if (sc_stream_sign_init(&conn->crypto_ctx, &sign_state) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_send_one: sign_init failed svc_id=%u", rconn->svc_id);
u_free(dgram); if (!seq_flags) rconn->tx_seq--; return -1;
u_free(dgram); if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1;
}
size_t data_len = SVC_ROUTE_HDR_SIZE + pl_len;
if (sc_stream_sign_update(&sign_state, dgram, data_len) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_send_one: sign_update failed svc_id=%u", rconn->svc_id);
sc_stream_sign_cleanup(&sign_state); u_free(dgram); if (!seq_flags) rconn->tx_seq--; return -1;
sc_stream_sign_cleanup(&sign_state); u_free(dgram); if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1;
}
size_t actual_sig_len = SC_SIGN_SIZE;
if (sc_stream_sign_final(&sign_state, dgram + data_len, &actual_sig_len) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_send_one: sign_final failed svc_id=%u", rconn->svc_id);
u_free(dgram); if (!seq_flags) rconn->tx_seq--; return -1;
u_free(dgram); if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1;
}
}
struct ll_entry* entry = queue_entry_new(0);
if (!entry) { u_free(dgram); if (!seq_flags) rconn->tx_seq--; return -1; }
if (!entry) { u_free(dgram); if (!seq_flags) rconn->tx_seq--; rconn->c_pkts_send_err++; return -1; }
entry->dgram = dgram;
entry->len = total_len;
@ -123,7 +123,16 @@ static int router_send_one_flags(struct ETCP_ROUTER_CONN* rconn, const uint8_t*
(int32_t)(rconn->tx_seq - rconn->tx_acked),
is_signed,
(unsigned long long)rconn->remote_node_id);
return etcp_send(conn, entry);
int ret = etcp_send(conn, entry);
if (ret != 0) {
if (!seq_flags) rconn->tx_seq--;
queue_dgram_free(entry); queue_entry_free(entry);
rconn->c_pkts_send_err++;
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_send_one: etcp_send failed ret=%d svc_id=%u seq=%u", ret, rconn->svc_id, seq);
} else {
rconn->c_pkts_sent++;
}
return ret;
}
// Отправка без conn (RST для неизвестного src)
@ -143,7 +152,11 @@ static void router_send_to(struct UTUN_INSTANCE* inst, uint64_t dst, uint8_t svc
entry->len = SVC_ROUTE_HDR_SIZE;
DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "router_send_to: seq_flags=0x%08x → %016llx svc_id=%u",
seq_flags, (unsigned long long)dst, svc_id);
etcp_send(conn, entry);
int ret = etcp_send(conn, entry);
if (ret != 0) {
queue_dgram_free(entry); queue_entry_free(entry);
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_send_to: etcp_send failed ret=%d", ret);
}
}
static void router_send_close_to_service(struct ETCP_ROUTER_CONN* rconn) {
@ -199,8 +212,9 @@ static void router_drain_send_q(struct ETCP_ROUTER_CONN* rconn) {
if ((int32_t)(rconn->tx_seq - rconn->tx_acked) >= ROUTER_MAX_INFLIGHT) break;
struct ll_entry* e = queue_data_get(rconn->send_q);
if (!e) { rconn->send_blocked = 0; break; }
router_send_one(rconn, e->dgram, e->len);
int s_err = router_send_one(rconn, e->dgram, e->len);
queue_dgram_free(e); queue_entry_free(e);
if (s_err != 0 && (int32_t)(rconn->tx_seq - rconn->tx_acked) >= ROUTER_MAX_INFLIGHT) break;
}
if (rconn->send_blocked && !rconn->send_resume_timer)
rconn->send_resume_timer = uasync_set_timeout(rconn->inst->ua,
@ -245,8 +259,6 @@ static int router_enqueue_send(struct ETCP_ROUTER_CONN* rconn, const uint8_t* pa
static void router_ack_do_send(struct ETCP_ROUTER_CONN* rconn) {
router_send_ack(rconn);
rconn->last_sent_ack_seq = rconn->rx_seq;
rconn->last_ack_sent_tb = get_time_tb();
}
static void router_send_ack(struct ETCP_ROUTER_CONN* rconn) {
@ -255,6 +267,7 @@ static void router_send_ack(struct ETCP_ROUTER_CONN* rconn) {
if (!conn) {
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router_ack: no route to %016llx svc_id=%u",
(unsigned long long)rconn->remote_node_id, rconn->svc_id);
rconn->last_ack_sent_tb = get_time_tb();
return;
}
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)u_malloc(SVC_ROUTE_HDR_SIZE);
@ -273,7 +286,15 @@ static void router_send_ack(struct ETCP_ROUTER_CONN* rconn) {
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "ACK_SEND: svc_id=%u rx_seq=%u → %016llx",
rconn->svc_id, rconn->rx_seq, (unsigned long long)rconn->remote_node_id);
etcp_send(conn, entry);
int ret = etcp_send(conn, entry);
if (ret != 0) {
queue_dgram_free(entry); queue_entry_free(entry);
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_ack: etcp_send failed ret=%d svc_id=%u rx_seq=%u", ret, rconn->svc_id, rconn->rx_seq);
return;
}
rconn->c_ack_sent++;
rconn->last_sent_ack_seq = rconn->rx_seq;
rconn->last_ack_sent_tb = get_time_tb();
}
static void router_schedule_ack(struct ETCP_ROUTER_CONN* rconn) {
@ -338,6 +359,7 @@ static void router_deliver(struct ETCP_ROUTER_CONN* rconn, struct ETCP_CONN* con
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "router_deliver: svc_id=%u len=%zu from remote=%016llx",
rconn->svc_id, payload_len, (unsigned long long)rconn->remote_node_id);
rconn->c_pkts_rcvd++;
cb(conn, svc_entry);
}
@ -415,6 +437,10 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
}
if (sc_stream_sign_verify(&vfy_state, sig, SC_SIGN_SIZE) != SC_OK) {
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: signature verification FAILED for node %016llx svc_id=%u — dropping", (unsigned long long)hdr->src_node_id, hdr->svc_id);
{
struct ETCP_ROUTER_CONN* sr = router_conn_find(inst, hdr->src_node_id, hdr->svc_id);
if (sr) sr->c_sign_fail++;
}
queue_dgram_free(entry); queue_entry_free(entry);
return;
}
@ -440,9 +466,11 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
rconn->svc_id, hdr->seq, (int32_t)(rconn->tx_seq - rconn->tx_acked),
queue_entry_count(rconn->send_q),
(unsigned long long)hdr->src_node_id);
rconn->c_ack_recv++;
} else {
DEBUG_WARN(DEBUG_CATEGORY_ETCPROUTE, "router: stale ACK seq=%u tx_acked=%u from %016llx, ignoring",
hdr->seq, rconn->tx_acked, (unsigned long long)hdr->src_node_id);
rconn->c_stale_ack++;
}
rconn->last_dgram_ts = get_current_timestamp();
if (rconn->send_blocked) router_drain_send_q(rconn);
@ -492,6 +520,7 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
if (d > ROUTER_MAX_INFLIGHT || d < -ROUTER_MAX_INFLIGHT) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router: seq=%u out of bounds, rx_seq=%u (d=%d), dropping",
seq, rconn->rx_seq, d);
rconn->c_oob_dropped++;
queue_dgram_free(entry); queue_entry_free(entry);
return;
}
@ -501,6 +530,7 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
if (((int32_t)(rconn->rx_seq - seq) > 0) ||
queue_find_data_by_index(rconn->recv_q, &seq)) {
DEBUG_DEBUG(DEBUG_CATEGORY_ETCPROUTE, "router: dup seq=%u rx_seq=%u, dropping", seq, rconn->rx_seq);
rconn->c_dup_dropped++;
queue_dgram_free(entry); queue_entry_free(entry);
return;
}
@ -535,7 +565,11 @@ static void etcp_router_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry)
}
DEBUG_TRACE(DEBUG_CATEGORY_ETCPROUTE, "etcp_router: forwarding svc_id=%u → %016llx via %s",
hdr->svc_id, (unsigned long long)hdr->dst_node_id, next->log_name);
etcp_send(next, entry);
int fwd_err = etcp_send(next, entry);
if (fwd_err != 0) {
queue_dgram_free(entry); queue_entry_free(entry);
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "etcp_router: transit etcp_send failed ret=%d", fwd_err);
}
}
}
@ -720,6 +754,15 @@ void etcp_router_conn_restart(struct UTUN_INSTANCE* inst, uint64_t remote_node_i
rconn->peer_sess_id = 0;
rconn->start_sent = 0;
rconn->send_blocked = 0;
rconn->c_pkts_sent = 0;
rconn->c_pkts_send_err = 0;
rconn->c_pkts_rcvd = 0;
rconn->c_ack_sent = 0;
rconn->c_ack_recv = 0;
rconn->c_dup_dropped = 0;
rconn->c_oob_dropped = 0;
rconn->c_stale_ack = 0;
rconn->c_sign_fail = 0;
}
void etcp_router_on_send_ready(struct UTUN_INSTANCE* inst, uint64_t node_id, uint8_t svc_id,
@ -768,6 +811,15 @@ struct ETCP_ROUTER_CONN* etcp_router_conn_get(struct UTUN_INSTANCE* inst,
rconn->sess_id = 0;
rconn->peer_sess_id = 0;
rconn->start_sent = 0;
rconn->c_pkts_sent = 0;
rconn->c_pkts_send_err = 0;
rconn->c_pkts_rcvd = 0;
rconn->c_ack_sent = 0;
rconn->c_ack_recv = 0;
rconn->c_dup_dropped = 0;
rconn->c_oob_dropped = 0;
rconn->c_stale_ack = 0;
rconn->c_sign_fail = 0;
rconn->recv_q = queue_new(inst->ua, ROUTER_RECVQ_HASH_SIZE, 0, 4, "router_recv_q");
if (!rconn->recv_q) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "router_conn_get: queue_new(recv_q) failed"); queue_entry_free(&rconn->ll); return NULL; }
rconn->send_q = queue_new(inst->ua, 0, 0, 0, "router_send_q");

10
src/etcp_router.h

@ -56,6 +56,16 @@ struct ETCP_ROUTER_CONN {
uint8_t sess_id; // наш session id (0-3)
uint8_t peer_sess_id; // последний sess_id от peer'а
uint8_t start_sent; // 0 = нужно отправить START в первом data
uint32_t c_pkts_sent; // успешные отправки данных
uint32_t c_pkts_send_err; // ошибки отправки
uint32_t c_pkts_rcvd; // получено и доставлено данных
uint32_t c_ack_sent; // отправлено ACK
uint32_t c_ack_recv; // получено ACK (последовательных)
uint32_t c_dup_dropped; // дропнуто дубликатов seq
uint32_t c_oob_dropped; // дропнуто out-of-bounds seq
uint32_t c_stale_ack; // устаревших ACK
uint32_t c_sign_fail; // signature verification failures
};
#define ROUTER_CONN_HASH_SIZE 256

8
tests/test_etcp_router_unit.c

@ -525,12 +525,8 @@ static int test_ack_timer(void) {
uint8_t data[] = { TEST_SVC_ID, 0x55, 0 };
inject(recv_cb, &inst, TEST_REMOTE_NODE, TEST_SVC_ID, 0, data + 1, 2, 0, 0);
if (c->ack_timer == NULL && c->last_sent_ack_seq != 1) FAIL("ack not sent (no timer, no immediate)");
if (c->ack_timer != NULL && c->last_sent_ack_seq != 0) FAIL("last_sent_ack_seq changed before timer fired");
// Cancel timer manually (it would fire in real event loop)
if (c->ack_timer) uasync_cancel_timeout(ua, c->ack_timer);
c->ack_timer = NULL;
if (c->ack_timer != NULL) FAIL("ack_timer set without BGP route");
if (c->last_sent_ack_seq != 0) FAIL("last_sent_ack_seq changed without BGP route");
etcp_router_conn_close(c);
TEARDOWN();

79
tools/etcpmon/etcpmon_gui.c

@ -20,7 +20,7 @@
//#pragma comment(lib, "user32.lib")
//#pragma comment(lib, "gdi32.lib")
#define WINDOW_WIDTH 1000
#define WINDOW_HEIGHT 1300
#define WINDOW_HEIGHT 1440
#define WINDOW_CLIENT_W 1250
#define UPDATE_INTERVAL 10 /* 50ms → 20 samples per second */
/* Global app pointer for callbacks */
@ -750,11 +750,57 @@ static void CreateControls(struct etcpmon_app* app) {
q_col1 + 85 + i * 65, qy - 2, 60, 18, hWnd, (HMENU)((UINT_PTR)(IDC_EDIT_DEBUG_0 + i)), hInst, NULL);
}
/* ========================================================================
* Router Congestion group — below Queues & Errors
* ======================================================================== */
{
int ry = 1260;
int r_col1 = 20, r_col2 = 260, r_col3 = 500, r_col4 = 740;
int lw = 85, ew = 70; /* label width, edit width */
CreateWindowExA(0, "BUTTON", "Router Congestion",
WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
10, ry, WINDOW_WIDTH - 20, 140, hWnd, (HMENU)IDC_GB_ROUTER, hInst, NULL);
/* Row 1 */
int ry1 = ry + 22;
CreateWindowExA(0, "STATIC", "Conns:", WS_CHILD | WS_VISIBLE, r_col1, ry1, 50, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrConns = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col1 + 55, ry1 - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_RTR_CONNS, hInst, NULL);
CreateWindowExA(0, "STATIC", "Inflight:", WS_CHILD | WS_VISIBLE, r_col2, ry1, 55, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrInflight = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col2 + 60, ry1 - 2, 70, 18, hWnd, (HMENU)IDC_EDIT_RTR_INFLIGHT, hInst, NULL);
CreateWindowExA(0, "STATIC", "SendQ:", WS_CHILD | WS_VISIBLE, r_col3, ry1, 55, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrSendQ = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col3 + 55, ry1 - 2, 70, 18, hWnd, (HMENU)IDC_EDIT_RTR_SENDQ, hInst, NULL);
CreateWindowExA(0, "STATIC", "RecvQ:", WS_CHILD | WS_VISIBLE, r_col4, ry1, 55, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrRecvQ = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col4 + 55, ry1 - 2, 70, 18, hWnd, (HMENU)IDC_EDIT_RTR_RECVQ, hInst, NULL);
/* Row 2 */
int ry2 = ry + 47;
CreateWindowExA(0, "STATIC", "Pkts Sent:", WS_CHILD | WS_VISIBLE, r_col1, ry2, lw, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrPktsSent = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col1 + lw, ry2 - 2, ew, 18, hWnd, (HMENU)IDC_EDIT_RTR_PKTS_SENT, hInst, NULL);
CreateWindowExA(0, "STATIC", "Send Err:", WS_CHILD | WS_VISIBLE, r_col2, ry2, lw, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrSendErr = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col2 + lw, ry2 - 2, ew, 18, hWnd, (HMENU)IDC_EDIT_RTR_SEND_ERR, hInst, NULL);
CreateWindowExA(0, "STATIC", "Pkts Rcvd:", WS_CHILD | WS_VISIBLE, r_col3, ry2, lw, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrPktsRcvd = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col3 + lw, ry2 - 2, ew, 18, hWnd, (HMENU)IDC_EDIT_RTR_PKTS_RCVD, hInst, NULL);
CreateWindowExA(0, "STATIC", "SignFail:", WS_CHILD | WS_VISIBLE, r_col4, ry2, lw, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrSignFail = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col4 + lw, ry2 - 2, ew, 18, hWnd, (HMENU)IDC_EDIT_RTR_SIGN_FAIL, hInst, NULL);
/* Row 3 */
int ry3 = ry + 72;
CreateWindowExA(0, "STATIC", "ACK Sent:", WS_CHILD | WS_VISIBLE, r_col1, ry3, lw, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrAckSent = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col1 + lw, ry3 - 2, ew, 18, hWnd, (HMENU)IDC_EDIT_RTR_ACK_SENT, hInst, NULL);
CreateWindowExA(0, "STATIC", "ACK Rcvd:", WS_CHILD | WS_VISIBLE, r_col2, ry3, lw, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrAckRecv = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col2 + lw, ry3 - 2, ew, 18, hWnd, (HMENU)IDC_EDIT_RTR_ACK_RECV, hInst, NULL);
CreateWindowExA(0, "STATIC", "Stale ACK:", WS_CHILD | WS_VISIBLE, r_col3, ry3, lw, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrStaleAck = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col3 + lw, ry3 - 2, ew, 18, hWnd, (HMENU)IDC_EDIT_RTR_STALE_ACK, hInst, NULL);
/* Row 4 */
int ry4 = ry + 97;
CreateWindowExA(0, "STATIC", "Dup Drop:", WS_CHILD | WS_VISIBLE, r_col1, ry4, lw, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrDupDrop = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col1 + lw, ry4 - 2, ew, 18, hWnd, (HMENU)IDC_EDIT_RTR_DUP_DROP, hInst, NULL);
CreateWindowExA(0, "STATIC", "OOB Drop:", WS_CHILD | WS_VISIBLE, r_col2, ry4, lw, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditRtrOobDrop = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, r_col2 + lw, ry4 - 2, ew, 18, hWnd, (HMENU)IDC_EDIT_RTR_OOB_DROP, hInst, NULL);
}
/* ========================================================================
* Debug Levels section — right column
* ======================================================================== */
{
int dy = 485;
int dy = 645;
app->hDebugGroupBox = CreateWindowExA(0, "BUTTON", "Debug Levels",
WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
1005, dy, 240, 545, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
@ -1586,6 +1632,21 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app,
UpdateEditIfChanged(hMain, IDC_EDIT_RT_BGP_SENDERS, "%u", metrics->tun.rt_bgp_senders);
UpdateEditIfChanged(hMain, IDC_EDIT_RT_BGP_NODES, "%u", metrics->tun.rt_bgp_nodes);
/* Router Congestion Metrics */
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_CONNS, "%u", metrics->router.total_conns);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_INFLIGHT, "%u", metrics->router.total_inflight);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_SENDQ, "%u", metrics->router.total_send_q);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_RECVQ, "%u", metrics->router.total_recv_q);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_PKTS_SENT, "%u", metrics->router.pkts_sent);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_SEND_ERR, "%u", metrics->router.pkts_send_err);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_PKTS_RCVD, "%u", metrics->router.pkts_rcvd);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_ACK_SENT, "%u", metrics->router.ack_sent);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_ACK_RECV, "%u", metrics->router.ack_recv);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_DUP_DROP, "%u", metrics->router.dup_dropped);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_OOB_DROP, "%u", metrics->router.oob_dropped);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_STALE_ACK, "%u", metrics->router.stale_ack);
UpdateEditIfChanged(hMain, IDC_EDIT_RTR_SIGN_FAIL, "%u", metrics->router.sign_fail);
/* 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);
@ -1757,6 +1818,20 @@ void etcpmon_gui_clear_metrics(struct etcpmon_app* app) {
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_BGP_SENDERS, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RT_BGP_NODES, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_CONNS, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_INFLIGHT, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_SENDQ, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_RECVQ, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_PKTS_SENT, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_SEND_ERR, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_PKTS_RCVD, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_ACK_SENT, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_ACK_RECV, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_DUP_DROP, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_OOB_DROP, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_STALE_ACK, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_RTR_SIGN_FAIL, "");
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, "");

31
tools/etcpmon/etcpmon_gui.h

@ -81,6 +81,22 @@ extern "C" {
#define IDC_EDIT_RT_BGP_SENDERS 315
#define IDC_EDIT_RT_BGP_NODES 316
/* Router Congestion control IDs */
#define IDC_GB_ROUTER 350
#define IDC_EDIT_RTR_CONNS 351
#define IDC_EDIT_RTR_INFLIGHT 352
#define IDC_EDIT_RTR_SENDQ 353
#define IDC_EDIT_RTR_RECVQ 354
#define IDC_EDIT_RTR_PKTS_SENT 355
#define IDC_EDIT_RTR_SEND_ERR 356
#define IDC_EDIT_RTR_PKTS_RCVD 357
#define IDC_EDIT_RTR_ACK_SENT 358
#define IDC_EDIT_RTR_ACK_RECV 359
#define IDC_EDIT_RTR_DUP_DROP 360
#define IDC_EDIT_RTR_OOB_DROP 361
#define IDC_EDIT_RTR_STALE_ACK 362
#define IDC_EDIT_RTR_SIGN_FAIL 363
/* Link list control ID */
#define IDC_LIST_LINKS 400
@ -252,6 +268,21 @@ struct etcpmon_app {
HWND hEditRtBgpSenders;
HWND hEditRtBgpNodes;
/* Router Congestion controls */
HWND hEditRtrConns;
HWND hEditRtrInflight;
HWND hEditRtrSendQ;
HWND hEditRtrRecvQ;
HWND hEditRtrPktsSent;
HWND hEditRtrSendErr;
HWND hEditRtrPktsRcvd;
HWND hEditRtrAckSent;
HWND hEditRtrAckRecv;
HWND hEditRtrDupDrop;
HWND hEditRtrOobDrop;
HWND hEditRtrStaleAck;
HWND hEditRtrSignFail;
/* Links list */
HWND hListLinks;

22
tools/etcpmon/etcpmon_protocol.h

@ -289,9 +289,27 @@ struct etcpmon_tun_metrics {
uint32_t rt_bgp_nodes; /* BGP nodes count (ROUTE_BGP) */
};
/* Router congestion metrics — aggregated over all router_conns */
struct etcpmon_router_metrics {
uint32_t total_conns;
uint32_t total_inflight;
uint32_t total_send_q;
uint32_t total_recv_q;
uint32_t pkts_sent;
uint32_t pkts_send_err;
uint32_t pkts_rcvd;
uint32_t ack_sent;
uint32_t ack_recv;
uint32_t dup_dropped;
uint32_t oob_dropped;
uint32_t stale_ack;
uint32_t sign_fail;
};
struct etcpmon_rsp_metrics {
struct etcpmon_etcp_metrics etcp; /* ETCP connection metrics */
struct etcpmon_tun_metrics tun; /* TUN interface metrics */
struct etcpmon_etcp_metrics etcp; /* ETCP connection metrics */
struct etcpmon_tun_metrics tun; /* TUN interface metrics */
struct etcpmon_router_metrics router; /* Router congestion metrics (aggregated) */
/* Followed by etcp.links_count * struct etcpmon_link_metrics */
};

Loading…
Cancel
Save