# Dummynet — UDP Network Emulator ## 1. Назначение Эмулятор сетевых условий для тестирования: задержка (фиксированная + случайная), ограничение пропускной способности (token bucket) и случайные потери пакетов. Два режима работы: **FULL** (автономный UDP-прокси между портами) и **INLINE** (встраиваемый фильтр в `send_hook` ETCP_LINK без создания своего сокета). ## 2. Как пользоваться ### Режим FULL (автономный UDP-прокси) 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. ``` [port-1] → [dummynet: delay→loss→shaper] → [dest_forward] [port+1] → [dummynet: delay→loss→shaper] → [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)` — настройка. 3. `dummynet_filter_attach(df, link)` — встраивается в `link->send_hook`, перехватывая все вызовы `socket_sendto`. 4. Дополнительно: `dummynet_filter_block_addr/unblock_addr` — блокировка отправки на конкретные адреса. ### Механизмы эмуляции | Механизм | Реализация | |----------|-----------| | **Delay** (fixed + random) | При приёме пакета создаётся uasync-таймер (`dummynet_delay_callback`). После срабатывания пакет кладётся в ll_queue направления | | **Bandwidth (token bucket)** | Shaper-таймер забирает из очереди по одному пакету с интервалом `len × 8 / bw_kbps` (timebase 0.1ms). Гарантирует не более `bandwidth_kbps` | | **Loss (permille)** | При приёме: `rand() % 1000 < loss_permille` → дроп. В INLINE-режиме — в хуке отправки | ### Статистика Структура `dummynet_stats`: `recv`, `sent`, `dropped` (переполнение очереди), `lost` (random loss), `queue_size` (текущий), `queue_max` (пиковый). Дополнительные отладочные счётчики: `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`. - INLINE-фильтр в режиме блокировки адреса не дропает пакет, а возвращает `len` (пакет «успешно отправлен», но фактически никуда не ушёл). ## 3. API ### FULL-режим | Функция | Назначение | |---------|------------| | `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_get_stats(dn, dir)` | Получить статистику направления | | `dummynet_reset_stats(dn, dir)` | Сбросить статистику (-1 = все направления) | | `dummynet_get_socket(dn)` | Вернуть fd сокета | | `dummynet_get_listen_port(dn)` | Вернуть listen_port | | `dummynet_get_uasync(dn)` | Вернуть указатель на UASYNC | | `dummynet_get_queue_size(dn, dir)` | Вернуть текущий размер очереди направления | | `dummynet_get_debug_counters(dn, dir, ...)` | Вернуть отладочные счётчики таймеров | ### INLINE-режим (dummynet_filter) | Функция | Назначение | |---------|------------| | `dummynet_filter_create(ua)` | Создать фильтр | | `dummynet_filter_set_loss(df, permille)` | Установить вероятность потерь | | `dummynet_filter_set_delay(df, delay_ms, jitter_ms)` | Установить задержку (NOTE: в текущей реализации delay не применяется в хуке) | | `dummynet_filter_attach(df, link)` | Прикрепить хук к ETCP_LINK | | `dummynet_filter_detach(df)` | Открепить хук | | `dummynet_filter_destroy(df)` | Уничтожить фильтр | | `dummynet_filter_get_stats(df)` | Получить статистику | | `dummynet_filter_block_addr(df, ip, port)` | Заблокировать адрес (до 4 адресов) | | `dummynet_filter_unblock_addr(df, ip, port)` | Разблокировать адрес | ### Структуры | Структура | Назначение | |-----------|------------| | `dummynet_stats` | Статистика: `recv`, `sent`, `dropped`, `lost`, `queue_size`, `queue_max` | | `dummynet_dir` | Внутренняя: параметры направления, очередь, таймеры шейпера, отладочные счётчики | | `dummynet` | Контекст FULL-режима: ua, сокет, два `dummynet_dir`, пул пакетов | | `dummynet_filter` | Контекст INLINE-режима: ua, loss_permille, delay, link, статистика, список блокировок | ### Зависимости `u_async.h`, `ll_queue.h`, `memory_pool.h`, `socket_compat.h`, `etcp_connections.h` (для ETCP_LINK), `platform_compat.h`