From 0b5a892a889c835df6f8a9aaa8dea85cf955bb76 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 22 Oct 2026 23:36:21 +0200 Subject: [PATCH] Document multipath acceptance criteria and reproduced protocol limitations --- doc/tasks.md | 19 +++++++++++++++++++ src/transport_layer/dummynet_doc.md | 29 ++++++++++++++++++----------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/doc/tasks.md b/doc/tasks.md index 1009da2f..016732b7 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -4,6 +4,25 @@ ## Текущие задачи +[ ] **ETCP: полезная утилизация нескольких каналов и доставка при зависании части линков** — тестовый стенд добавлен 22.10.2026: + test_dummynet_channels калибрует BWlim 2/8 Мбит/с на смешанных размерах, delay, ограниченный HOLD, + выпуск с BWlim, DROP ожидающих пакетов и уничтожение с активными delay/shaper. Включён в обычный Linux-набор. + dummynet хранит все delay callbacks, сериализация не теряет доли миллисекунды, добавлены режимы RUN/DROP/HOLD. + test_etcp_multipath использует настоящие instance/NCD/ETCP/BBR, независимые UDP-прокси и пассивное наблюдение пакетов. + Полный запуск: make -C tests check-multipath; один сценарий: tests/test_etcp_multipath <имя>. + Профили: equal, bandwidth, rtt, fast-distant, slow-distant, three, bidirectional; + отказы: drop, hold, drop-forward, drop-reverse, short-hold, slow-drop, two-stuck, load-drop, load-hold. + UTUN_MULTIPATH_CSV=/tmp/multipath.csv сохраняет очереди, RTT, pacing, inflight/cwnd, повторы и доставку по фазам. + Пороги: wire >=90% BWlim каждого канала, уникальные DATA >=80%, полезная скорость >=85% суммы BWlim + и >=90% суммы отдельных измерений. Выдача старой очереди сборки не может завысить полезную скорость. + При отказе: доставка до восстановления пути, пауза <=100мс и latency <=100мс при ограниченном источнике; + при насыщении оставшийся набор должен давать >=85% своей ёмкости после переходного периода. + Начальные прогоны выявили нарушения: RTT 20/20мс, DROP одного пути — пауза 204мс, latency 344мс; + при разных RTT/BWlim не выполняются требования утилизации, в том числе из-за повторов и переполнения очередей. + Протокольный фикс не вносился. Отдельно проверить выбор пути повторов, общий RTO, BBR/pacing и блокировку сборки. + После исправлений добавить смену профилей на ходу, повторяющиеся отказы и смешанный UDP/STCP со stalled TCP write. + Полная матрица дольше 90s общего runner и запускается отдельной целью; нарушения завершают её с ошибкой. + [+] **ETCP: единый установщик прямого транспорта через NCD** — исправлено 22.10.2026: Удалён неиспользуемый рабочим кодом etcp_connect с EARLY/LATE, отдельными линками и таймерами; три тестовых файла переведены на NCD handles с начала подключения. Сохранены проверки независимых владельцев, diff --git a/src/transport_layer/dummynet_doc.md b/src/transport_layer/dummynet_doc.md index 6cb33ff1..b730fdde 100644 --- a/src/transport_layer/dummynet_doc.md +++ b/src/transport_layer/dummynet_doc.md @@ -1,7 +1,7 @@ # Dummynet — UDP Network Emulator ## 1. Назначение -Эмулятор сетевых условий для тестирования: задержка (фиксированная + случайная), ограничение пропускной способности (token bucket) и случайные потери пакетов. Два режима работы: **FULL** (автономный UDP-прокси между портами) и **INLINE** (встраиваемый фильтр в `send_hook` ETCP_LINK без создания своего сокета). +Эмулятор сетевых условий: задержка (фиксированная + случайная), сериализация с BWlim и потери пакетов. **FULL** — UDP-прокси между явно заданными endpoints; **INLINE** — фильтр потерь в `send_hook` ETCP_LINK. Задержка и BWlim реализованы в FULL. ## 2. Как пользоваться @@ -9,17 +9,17 @@ 1. `dummynet_create(ua, bind_ip, listen_port)` — создаёт контекст, открывает UDP-сокет на `listen_port`. 2. `dummynet_set_direction(dn, DUMMYNET_FORWARD, ...)` и `DUMMYNET_BACKWARD` — настраивает параметры для каждого направления. -3. Пакеты от `listen_port-1` идут в направлении FORWARD, от `listen_port+1` — в BACKWARD. +3. Источник FORWARD — endpoint, заданный как назначение BACKWARD, и наоборот. Порты независимы; `listen_port=0` выбирает ОС. ``` -[port-1] → [dummynet: delay→loss→shaper] → [dest_forward] -[port+1] → [dummynet: delay→loss→shaper] → [dest_backward] +[dest_backward] → [dummynet: loss/queue limit→delay→serializer] → [dest_forward] +[dest_forward] → [dummynet: loss/queue limit→delay→serializer] → [dest_backward] ``` ### Режим INLINE (send_hook в ETCP_LINK) 1. `dummynet_filter_create(ua)` — создаёт фильтр (нет своего сокета). -2. `dummynet_filter_set_loss(df, permille)` / `dummynet_filter_set_delay(df, ms, jitter_ms)` — настройка. +2. `dummynet_filter_set_loss(df, permille)` — настройка потерь. `set_delay` пока только сохраняет параметры. 3. `dummynet_filter_attach(df, link)` — встраивается в `link->send_hook`, перехватывая все вызовы `socket_sendto`. 4. Дополнительно: `dummynet_filter_block_addr/unblock_addr` — блокировка отправки на конкретные адреса. @@ -28,18 +28,24 @@ | Механизм | Реализация | |----------|-----------| | **Delay** (fixed + random) | При приёме пакета создаётся uasync-таймер (`dummynet_delay_callback`). После срабатывания пакет кладётся в ll_queue направления | -| **Bandwidth (token bucket)** | Shaper-таймер забирает из очереди по одному пакету с интервалом `len × 8 / bw_kbps` (timebase 0.1ms). Гарантирует не более `bandwidth_kbps` | +| **Bandwidth (serializer)** | Срок передачи увеличивается на время сериализации текущего пакета; дробные миллисекунды сохраняются. Один таймер направления выпускает все уже готовые пакеты, без накопления ошибки округления таймера | | **Loss (permille)** | При приёме: `rand() % 1000 < loss_permille` → дроп. В INLINE-режиме — в хуке отправки | +| **DROP** | `dummynet_set_mode(dn, dir, DUMMYNET_DROP)` теряет новые пакеты и удаляет уже ожидающие, включая delay | +| **HOLD** | Останавливает сериализацию, сохраняя ограниченную очередь. RUN начинает сериализацию головы заново; накопленное выпускается с BWlim | ### Статистика -Структура `dummynet_stats`: `recv`, `sent`, `dropped` (переполнение очереди), `lost` (random loss), `queue_size` (текущий), `queue_max` (пиковый). +`recv`/`sent` — число пакетов, `recv_bytes`/`sent_bytes` — UDP-байты без IP/UDP заголовков. +`dropped` — переполнение/ошибка ресурсов или отправки, `lost` — случайные потери и DROP, `blocked` — только DROP. +`queue_size`/`queue_max` учитывают все ожидающие пакеты, включая delay/HOLD. Сброс статистики сохраняет текущий размер очереди. Дополнительные отладочные счётчики: `delay_timer_set/fire`, `shaper_timer_set/fire`. ### Ключевые нюансы -- В FULL-режиме порты `listen_port-1`, `listen_port`, `listen_port+1` должны быть свободны. Направление определяется по порту источника. -- Шейпер использует burst allowance (`SHAPER_BURST_TB = 10 timebase units`), допуская небольшие всплески. -- При переполнении очереди (> `max_queue_pkts`) пакет дропается, увеличивается `dropped`. +- Оба направления нужно настроить до начала трафика; источник проверяется по IP и порту. +- BWlim задаётся в десятичных кбит/с по UDP-байтам; 0 означает unlimited. RTT без очередей — сумма задержек направлений и сериализации. +- Таймеры uasync имеют миллисекундную точность: несколько готовых пакетов могут выйти вместе; средняя скорость сохраняется. +- При достижении `max_queue_pkts` новый пакет отбрасывается. Лимит включает ещё не сработавшие delay-таймеры. +- Все операции — в потоке ua. Destroy отменяет также delay-таймеры, освобождает их аргументы и пакеты. - INLINE-фильтр в режиме блокировки адреса не дропает пакет, а возвращает `len` (пакет «успешно отправлен», но фактически никуда не ушёл). ## 3. API @@ -51,6 +57,7 @@ | `dummynet_create(ua, bind_ip, listen_port)` | Создать контекст, открыть UDP-сокет, зарегистрировать в uasync | | `dummynet_destroy(dn)` | Закрыть сокет, отменить таймеры, очистить очереди, освободить память | | `dummynet_set_direction(dn, dir, delay_fixed_ms, delay_random_ms, bw_kbps, max_q, loss_permille, dest_ip, dest_port)` | Настроить параметры направления | +| `dummynet_set_mode(dn, dir, mode)` | RUN/DROP/HOLD направления, 0 / -1 | | `dummynet_get_stats(dn, dir)` | Получить статистику направления | | `dummynet_reset_stats(dn, dir)` | Сбросить статистику (-1 = все направления) | | `dummynet_get_socket(dn)` | Вернуть fd сокета | @@ -77,7 +84,7 @@ | Структура | Назначение | |-----------|------------| -| `dummynet_stats` | Статистика: `recv`, `sent`, `dropped`, `lost`, `queue_size`, `queue_max` | +| `dummynet_stats` | Счётчики пакетов/байтов, потерь и размера очереди; точные поля — в dummynet.h | | `dummynet_dir` | Внутренняя: параметры направления, очередь, таймеры шейпера, отладочные счётчики | | `dummynet` | Контекст FULL-режима: ua, сокет, два `dummynet_dir`, пул пакетов | | `dummynet_filter` | Контекст INLINE-режима: ua, loss_permille, delay, link, статистика, список блокировок |