Browse Source

Add duplicate packet counter to ACK frames

- Add rx_dup_count (local) and tx_dup_count (remote via ACK) to ETCP_CONN
- Extend ACK section format: add 16-bit rx_dup_count after last_delivered_id
- Reconstruct 32-bit tx_dup_count from received 16-bit diff
- Update etcpmon protocol and control_server to expose counters
- Update packet dumper for new ACK format
congestion
Evgeny 5 months ago
parent
commit
385aa066b2
  1. 2
      src/control_server.c
  2. 26
      src/etcp.c
  3. 2
      src/etcp.h
  4. 7
      src/etcp_debug.c
  5. 2
      tools/etcpmon/etcpmon_protocol.h

2
src/control_server.c

@ -969,6 +969,8 @@ static void send_metrics(struct control_server* server, struct control_client* c
rsp->etcp.cnt_ack_hit_sndq = conn->cnt_ack_hit_sndq;
rsp->etcp.cnt_ack_miss = conn->cnt_ack_miss;
rsp->etcp.cnt_link_wait = conn->cnt_link_wait;
rsp->etcp.rx_dup_count = conn->rx_dup_count;
rsp->etcp.tx_dup_count = conn->tx_dup_count;
rsp->etcp.tx_state = conn->tx_state;
for (int i = 0; i < 8; i++) {
rsp->etcp.debug[i] = conn->debug[i];

26
src/etcp.c

@ -256,6 +256,8 @@ void etcp_conn_reset(struct ETCP_CONN* etcp) {
etcp->bytes_sent_total = 0;
etcp->retransmissions_count = 0;
etcp->ack_packets_count = 0;
etcp->rx_dup_count = 0;
etcp->tx_dup_count = 0;
// Reset RTT history
memset(etcp->rtt_history, 0, sizeof(etcp->rtt_history));
@ -504,6 +506,8 @@ void etcp_stats(struct ETCP_CONN* etcp) {
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] retransmissions_count: %u", etcp->log_name, etcp->retransmissions_count);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] ack_packets_count: %u", etcp->log_name, etcp->ack_packets_count);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] unacked_bytes: %u", etcp->log_name, etcp->unacked_bytes);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] rx_dup_count: %u", etcp->log_name, etcp->rx_dup_count);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] tx_dup_count: %u", etcp->log_name, etcp->tx_dup_count);
// IDs
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] IDs:", etcp->log_name);
@ -810,7 +814,7 @@ struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp) {
dgram->noencrypt_len=0;
dgram->timestamp = get_current_timestamp();
// формат ack: [01] [elements count] [4 байта last_delivered_id] и <[4 байта seq][2 байта recv_ts][2 байта txrx delay ts]> x count
// формат ack: [01] [elements count] [4 байта last_delivered_id] [2 байта rx_dup_count] и <[4 байта seq][2 байта recv_ts][2 байта txrx delay ts]> x count
dgram->data[0]=1;// ack
int ptr=2;
@ -819,9 +823,12 @@ struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp) {
dgram->data[ptr++]=etcp->last_delivered_id>>16;
dgram->data[ptr++]=etcp->last_delivered_id>>24;
dgram->data[ptr++]=etcp->rx_dup_count;
dgram->data[ptr++]=etcp->rx_dup_count>>8;
int data_len=0;
if (inf_pkt) data_len=inf_pkt->ll.len;
int remain_len=link->mtu -28/*udp headers*/ -13-8-4/*sc_nonce+tag size+crc*/ -9/*hdr[3] + min ack[6]*/ -5/*payload hdr*/ - data_len;
int remain_len=link->mtu -28/*udp headers*/ -13-8-4/*sc_nonce+tag size+crc*/ -11/*hdr[3] + min ack[8]*/ -5/*payload hdr*/ - data_len;
// DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "remain_len= %d pl=%d", remain_len, data_len);
// добавим опциональные заголовки
@ -851,7 +858,7 @@ struct ETCP_DGRAM* etcp_request_pkt(struct ETCP_CONN* etcp) {
if (ptr>500) break;
}
dgram->data[1]=ptr/8;
dgram->data[1]=(ptr - 8) / 8;
if (link->last_recv_updated && remain_len>=5) {// если есть данные - добавим channel_timestamp
@ -1035,13 +1042,17 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
case ETCP_SECTION_ACK: {
int elm_cnt=data[1];
uint32_t till=data[2] | (data[3]<<8) | (data[4]<<16) | (data[5]<<24);
int ack_section_len = 6 + elm_cnt * 8;
uint16_t rx_dup_count_16 = data[6] | (data[7]<<8);
uint16_t old_tx_dup_16 = etcp->tx_dup_count & 0xFFFF;
int16_t diff = (int16_t)(rx_dup_count_16 - old_tx_dup_16);
etcp->tx_dup_count += diff;
int ack_section_len = 8 + elm_cnt * 8;
data+=ack_section_len;
len-=ack_section_len;
for (int i=0; i<elm_cnt; i++) {
uint32_t seq=data[-ack_section_len+6+i*8] | (data[-ack_section_len+7+i*8]<<8) | (data[-ack_section_len+8+i*8]<<16) | (data[-ack_section_len+9+i*8]<<24);
uint16_t ts=data[-ack_section_len+10+i*8] | (data[-ack_section_len+11+i*8]<<8);
uint16_t dts=data[-ack_section_len+12+i*8] | (data[-ack_section_len+13+i*8]<<8);
uint32_t seq=data[-ack_section_len+8+i*8] | (data[-ack_section_len+9+i*8]<<8) | (data[-ack_section_len+10+i*8]<<16) | (data[-ack_section_len+11+i*8]<<24);
uint16_t ts=data[-ack_section_len+12+i*8] | (data[-ack_section_len+13+i*8]<<8);
uint16_t dts=data[-ack_section_len+14+i*8] | (data[-ack_section_len+15+i*8]<<8);
etcp_ack_recv(etcp, seq, ts, dts);
}
while ((int32_t)(etcp->rx_ack_till-till)<0) { etcp->rx_ack_till++; etcp_ack_recv(etcp, etcp->rx_ack_till, -1, -1); }// подтверждаем всё по till
@ -1190,6 +1201,7 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] RX seq=%u need=%u asm_len=%d", etcp->log_name, seq, etcp->last_delivered_id+1, etcp->recv_q->count);
if ((int32_t)(seq - etcp->last_delivered_id) == 1) etcp_output_try_assembly(etcp);// пробуем собрать выходную очередь из фрагментов
} else {
etcp->rx_dup_count++;
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] RX dup: seq=%u need=%u asm_len=%d", etcp->log_name, seq, etcp->last_delivered_id+1, etcp->recv_q->count);
}
} else DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "payload len %d < 5", len);

2
src/etcp.h

@ -165,6 +165,8 @@ struct ETCP_CONN {
uint32_t cnt_ack_hit_sndq; // счетчик удалений inflight пакетов из sndq
uint32_t cnt_ack_miss; // счетчик не найденных ack
uint32_t cnt_link_wait; // счетчик переходов в ожидание когда link busy
uint32_t rx_dup_count; // счетчик принятых дубликатов (локальные)
uint32_t tx_dup_count; // счетчик дубликатов удаленной стороны (из ACK)
uint32_t debug[8]; // 8 значений для дебага (live watch)
// Logging identifier (format: "XXXX→XXXX [name]" - last 4 digits of local and peer node_id + optional name)

7
src/etcp_debug.c

@ -42,11 +42,12 @@ void etcp_dump_pkt_sections(struct ETCP_DGRAM* pkt, struct ETCP_LINK* link, int
case ETCP_SECTION_ACK: {
if (offset + 2 > len) { offset = len; break; }
ack_count = data[offset + 1];
if (offset + 6 > len) { offset = len; break; }
if (offset + 8 > len) { offset = len; break; }
ack_last_delivered = data[offset + 2] | (data[offset + 3] << 8) |
(data[offset + 4] << 16) | (data[offset + 5] << 24);
pos += snprintf(buf + pos, sizeof(buf) - pos, " ack=%u/%d", ack_last_delivered, ack_count);
offset += 6 + ack_count * 8;
uint16_t ack_rx_dup = data[offset + 6] | (data[offset + 7] << 8);
pos += snprintf(buf + pos, sizeof(buf) - pos, " ack=%u/%d dup=%u", ack_last_delivered, ack_count, ack_rx_dup);
offset += 8 + ack_count * 8;
break;
}
case ETCP_SECTION_TIMESTAMP: {

2
tools/etcpmon/etcpmon_protocol.h

@ -190,6 +190,8 @@ struct etcpmon_etcp_metrics {
uint32_t cnt_ack_hit_sndq;
uint32_t cnt_ack_miss;
uint32_t cnt_link_wait;
uint32_t rx_dup_count;
uint32_t tx_dup_count;
uint32_t tx_state;
uint32_t debug[8];

Loading…
Cancel
Save