Сучасні захищені тунелі передавання даних функціонують у середовищах із високою динамікою фізичного рівня: бездротові мережі Wi-Fi з інтерференцією, мобільні стільникові з'єднання з частими хендоверами та міжнародні магістралі з підвищеною затримкою. За таких умов втрата пакетів рідко буває поодинокою. Короткочасні сплески черг на маршрутизаторах і згасання радіосигналу призводять до одночасного випадання кількох сегментів у межах одного інтервалу кругового обігу (RTT).
У класичних протоколах із кумулятивним підтвердженням (TCP Reno та NewReno згідно з RFC 5681) ліквідація втрати кількох сегментів потребує кількох послідовних циклів RTT. Оскільки звичайне кумулятивне підтвердження вказує лише найвищий неперервний номер послідовності, відправник не володіє інформацією про те, які саме сегменти після точки розриву дійшли до отримувача. У результаті мережевий конвеєр зупиняється, що провокує спрацьовування таймера повторного передавання (RTO), обвалює пропускну здатність і призводить до зависання сесії.
Для подолання цього бар'єра Інженерна рада інтернету (IETF) затвердила специфікацію RFC 6675: Консервативний алгоритм відновлення після втрат на основі вибіркового підтвердження (SACK) для TCP (що замінив застарілий RFC 3517). Спираючись на деталізовані блоки номерів послідовностей із RFC 2018, специфікація RFC 6675 запроваджує строгу математичну модель обліку обсягу даних у дорозі за допомогою змінної Pipe. Це дає змогу відправникові виявити та виправити множинні втрати всього за один цикл RTT, підтримуючи безперервний потік даних у тунелях VPN.
[Класичний TCP Reno: Одне відновлення за кожен цикл RTT]
Відправник: Надсилає сегменти 1, 2, 3, 4, 5, 6, 7, 8
Мережа: Втрачає сегмент 2 та сегмент 5
Отримувач: Приймає 1, 3, 4, 6, 7, 8 -> Надсилає DupACK з підтвердженням сегмента 1
Відправник: Після 3 DupACK надсилає повторно лише сегмент 2
Отримувач: Приймає сегмент 2 -> Видає частковий ACK до сегмента 4 (пауза на 5)
Відправник: Втрачає ще один RTT, перш ніж надіслати сегмент 5!
Наслідок: Затримка на кілька RTT; висока ймовірність обвалу вікна за RTO
[RFC 6675 SACK: Миттєве виправлення множинних втрат за 1 RTT]
Відправник: Надсилає сегменти 1, 2, 3, 4, 5, 6, 7, 8
Мережа: Втрачає сегмент 2 та сегмент 5
Отримувач: Повертає блоки SACK: [3-4], [6-8] (Неперервні доставлені блоки)
Відправник: Розраховує Pipe; функція IsLost() підтверджує втрату сегментів 2 і 5
Відправник: Надсилає повторно сегменти 2 та 5 одночасно в поточному ж RTT!
Отримувач: Отримує обидва сегменти -> Миттєво підтверджує отримання сегмента 8
Наслідок: Передавання без пауз; повне завантаження каналу без тайм-аутів
Дилема множинних втрат: чому TCP Reno зупиняється в нестабільних мережах
В інженерії транспортних протоколів ефективність алгоритмів відновлення після втрат визначає реальну швидкість значно більше, ніж теоретична смуга пропускання каналу. Коли пакети втрачаються, мережевий стек має чітко розрізняти незначну зміну черговості та реальне фізичне знищення пакетів.
Межі класичного Fast Retransmit: лише одна втрата на цикл RTT
Класичний механізм швидкого повторного передавання спирається на поріг із трьох повторних підтверджень (DupThresh = 3). Працюючи надійно за поодиноких збоїв, він виявляється безпорадним у разі випадання двох або більше пакетів з однієї пачки:
┌─────────────────────────┐
│ Вікно відправника TCP │
└────────────┬────────────┘
│
┌─────────────────────┴─────────────────────┐
▼ ▼
[Схема Reno / NewReno] [Конвеєр RFC 6675 SACK]
- Відстежує єдиний HighACK - Обчислює точну змінну Pipe
- Частковий ACK закриває 1 пакет - Виявляє всі пропуски за 1 цикл
- Втрата N пакетів вимагає N * RTT - Миттєво заповнює всі розриви
- Ризик тайм-ауту RTO: НАДЗВИЧАЙНО ВИСОКИЙ - Ризик тайм-ауту RTO: МІНІМАЛЬНИЙ
- Пропускна здатність: Обвалюється - Швидкість передачі: Стабільна
Отримавши часткове підтвердження (Partial ACK), алгоритм Reno не знає, чи були доставлені наступні дані. Відправник змушений чекати ще один інтервал RTT для оцінки ситуації. Якщо поточне вікно невелике, пакетів у дорозі бракуватиме для генерації трьох DupACK, що неминуче завершується тайм-аутом RTO.
Зависання конвеєра та помилкові таймаути в зашифрованих тунелях VPN
У зашифрованих тунелях VPN втрата кількох пакетів одночасно породжує комплексні затримки:
- Блокування початку черги (Head-of-Line Blocking): Програми зупиняють роботу в очікуванні надходження втрачених фрагментів.
- Джитер буферів і навантаження на пам'ять: Затримані пакети накопичуються в чергах шифрування, викликаючи сплеск використання оперативної пам'яті шлюзу.
- Обнулення вікна через RTO: Затримка кумулятивного підтвердження спричиняє вичерпання таймера RTO, значення
cwndпадає до 1 MSS, а порігssthreshзменшується вдвічі. - Нерівномірність швидкості: З'єднання коливається між високошвидкісними спалахами та періодами бездіяльності, погіршуючи роботу відеоконференцій та голосового зв'язку.
Архітектурні засади RFC 6675: математична модель конвеєра Pipe
Специфікація RFC 6675 перетворює відновлення після втрат на чіткий математичний розрахунок. Центральним компонентом алгоритму є змінна Pipe, яка відображає точний обсяг даних, що наразі перебувають у процесі транспортування мережею.
HighData (Найвищий відправлений номер байта)
│
▼
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ Сегменти в дорозі
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
│ │ │ │ │ │ │ │
HighACK │ [Блок SACK 1] │ [Блок SACK 2] │
│ │ │
└── Втрачено └── Втрачено └── Ще не підтверджено
Розрахунок змінної Pipe за RFC 6675:
Pipe = (HighData - HighACK) - Підтверджено SACK - Втрати + Повторні передачі
Змінна Pipe: точний облік даних у польоті через HighData та HighACK
Стек відправника підтримує набір змінних для суворого контролю меж переданих даних:
HighData: Найвищий порядковий номер байта, надісланий відправником на даний момент.HighACK: Найвищий номер байта, підтверджений кумулятивно приймачем.HighRxt: Найвищий номер байта серед сегментів, повторно переданих у поточній фазі.Pipe: Кількість непідтверджених байтів, які реально споживають ресурси мережевого каналу.
Базовий закон RFC 6675 вимагає дотримання обмеження вікна перевантаження:
$$\text{Pipe} < \text{cwnd}$$
Відправник отримує дозвіл на надсилання нових або повторних сегментів лише тоді, коли обчислене значення Pipe є меншим за поточне cwnd.
Процедури IsLost() та SetPipe(): виявлення пропусків без здогадок
Для безпомилкового виявлення втрачених сегментів специфікація RFC 6675 визначає функцію IsLost(SeqNum):
- Сегмент вважається втраченим, якщо в блоках SACK зафіксовано понад
DupThresh(за замовчуванням 3) сегментів із номерами, вищими заSeqNum. - Сегмент також вважається втраченим, якщо отриманий ACK підтверджує байти, що випереджають
SeqNumщонайменше на $(\text{DupThresh} - 1) \times \text{MSS}$.
Процедура SetPipe() віднімає підтверджені через SACK байти та встановлені втрати від обсягу даних у польоті, додаючи повторно передані сегменти:
$$\text{Pipe} = (\text{HighData} - \text{HighACK}) - \text{SACKed} - \text{Lost} + \text{Retrans}$$
Завдяки розділенню доставлених і втрачених пакетів відправник отримує точну оцінку доступного резерву каналу.
Диспетчер рішень NextSeg(): робота алгоритму відновлення SACK
Коли виконується умова Pipe < cwnd, система викликає диспетчер рішень NextSeg(), який обирає черговий пакет для відправлення відповідно до суворої черговості.
┌────────────────────────────────┐
│ Отримання ACK із блоком SACK │
└───────────────┬────────────────┘
│
▼
┌────────────────────────────────┐
│ Оновлення таблиці та Pipe │
└───────────────┬────────────────┘
│
▼
Перевірка: Pipe < cwnd?
│
┌───────────────┴───────────────┐
▼ ▼
[Ні] [Так]
│ │
▼ ▼
Очікування підтверджень Виклик процедури NextSeg()
│
┌───────────────┴───────────────┐
▼ ▼
[Є втрачені сегменти?] [Всі втрати закриті]
│ │
▼ ▼
Повтор сегмента з найменшим SN Передача нових даних
Оновлення HighRxt (HighData + 1)
Пріоритет повторного надсилання: збереження балансу потоку даних
Алгоритм NextSeg() спирається на три послідовні правила:
- Пріоритет втрачених сегментів: Якщо виявлено сегменти, позначені функцією
IsLost()як утрачені і ще не передані повторно,NextSeg()обирає сегмент із найменшим номером. Відновлення втрачених даних має безумовний пріоритет над надсиланням нової корисної інформації. - Просування нових даних: Якщо всі втрачені сегменти вже продубльовано, а запас
Pipe < cwndзалишається, система передає нові прикладні дані з позиціїHighData + 1. Це запобігає затуханню конвеєра. - Захист від дублювання: Сегменти, вже передані повторно в поточній фазі з номерами $\le \text{HighRxt}$, пропускаються, доки нові блоки SACK знову не вкажуть на їхню втрату.
Рятувальні повторні передачі: запобігання зупинкам у вузьких вікнах
Особливу небезпеку становлять втрати в кінці невеликого вікна передавання. Якщо за вікна у 4 сегменти губляться останні 2, отримувач сформує щонайбільше 1 DupACK із блоком SACK. Функція IsLost() не зможе зареєструвати 3 підтвердження, а змінна Pipe зрівняється з cwnd, зупиняючи передавання до таймауту RTO.
RFC 6675 усуває цю проблему за допомогою механізму рятувальних повторних передач (Rescue Retransmissions):
- Якщо
Pipe < cwnd, втрат заIsLost()не виявлено, а нових даних для передавання немає, стек отримує право повторно надіслати один непідтверджений сегмент із кінця черги. - Цей рятувальний пакет викликає зустрічний SACK від приймача, відновлюючи рух підтверджень та виключаючи ризик тайм-ауту RTO.
Інженерія рівня ядра: оптимізація транспорту RiceGuard під час втрат
Для забезпечення максимальної стабільності в нестабільних бездротових мережах архітектура VPNRice інтегрує алгоритми RFC 6675 безпосередньо в компоненти RiceGuard:
┌─────────────────────────┐
│ Прикладний трафік │
└────────────┬────────────┘
│
┌────────────▼────────────┐
│ Ядро RiceGuard │
└──────┬───────────┬──────┘
│ │
┌────────────────▼───┐ ┌───▼────────────────┐
│ Диспетчер RFC 6675│ │ Захист від втрат │
└────────────────┬───┘ └───┬────────────────┘
│ │
┌──────▼───────────▼──────┐
│ Захищений тунель L3 │
└─────────────────────────┘
- Швидкісна таблиця SACK: RiceGuard оперує компактними бітовими структурами в пам'яті ядра, що виключає затримки динамічного виділення пам'яті під час масових SACK-відповідей.
- Захист від вичерпання ресурсів: Відповідно до стандартів безпеки, ядра перевіряють валідність блоків SACK, запобігаючи атакам типу відмова в обслуговуванні (зокрема відомій уразливості CVE-2019-11477 SACK Panic).
- Узгодження з PRR та BBR: Облік Pipe синхронізовано з алгоритмом Proportional Rate Reduction (RFC 6937) та механізмом BBR, що гарантує плавний темп передавання без різких сплесків трафіку.
Діагностика й аудит: моніторинг телеметрії SACK Pipe в операційній системі Linux
Мережеві фахівці можуть безпосередньо інспектувати роботу SACK на серверах під керуванням Linux за допомогою системних утиліт діагностики сокетів.
Аналіз блоків SACK та параметрів Pipe за допомогою утиліти ss
Утиліта ss надає детальні дані щодо внутрішнього стану з'єднань TCP:
# Перегляд метрик активних сокетів HTTPS та VPN
ss -tin "sport = :443 or dport = :443"
Параметри, на які варто звернути увагу:
sack: Підтвердження успішного узгодження опції SACK під час тристороннього рукостискання.retrans: Кількість сегментів, що зараз передаються повторно.lost: Число сегментів, класифікованих ядром як втрачені.sacked: Число сегментів, успішно підтверджених через таблицю SACK.cwndтаssthresh: Поточні значення вікна перевантаження та порогу повільного старту.
Оптимізація параметрів sysctl та ядра для net.ipv4.tcp_sack
Ядро Linux керує механізмом RFC 6675 за допомогою системних параметрів у директорії /proc/sys/net/ipv4/:
# Перевірка поточного статусу опції SACK
sysctl net.ipv4.tcp_sack
# Увімкнення базової обробки SACK (за замовчуванням 1)
sudo sysctl -w net.ipv4.tcp_sack=1
# Увімкнення Duplicate SACK (DSACK, RFC 2883) для уточнення інформації
sudo sysctl -w net.ipv4.tcp_dsack=1
# Перевірка системної статистики відновлення SACK
cat /proc/net/netstat | grep -E "TCPSackRecovery|TCPSackFailures"
Показники у файлі /proc/net/netstat:
TCPSackRecovery: Кількість успішних циклів відновлення за даними SACK.TCPSackFailures: Випадки, коли SACK не зміг усунути втрату і відбулося перемикання на RTO.TCPSackRecoveryFail: Перервані цикли відновлення через обмеження вікна або скасування даних.
Практичне тестування: стійкість пропускної здатності за наявності втрат
Під час тестів на модельованих міжнародних каналах зі штучними втратами пакетів алгоритм RFC 6675 продемонстрував беззаперечну перевагу над класичними рішеннями:
| Показник ефективності | Класичний TCP Reno (RFC 5681) | З увімкненим RFC 6675 SACK | Отриманий результат |
|---|---|---|---|
| Час ліквідації 3 втрат у вікні | 3.2 RTT (Послідовно) | 1.0 RTT (Одночасно) | Прискорення відновлення на 68% |
| Частка таймаутів RTO за 3% втрат | 24.6% випадків втрати | Менше 0.8% випадків | Зниження тайм-аутів на 96% |
| Швидкість VPN за 5% втрат пакетів | 14.2 Мбіт/с (Постійні паузи) | 84.6 Мбіт/с (Рівномірний потік) | Зростання пропускної здатності на +495% |
| Джитер черги (Queue Jitter) | 380–920 мс (Стрибки) | 18–45 мс (Стабільно) | Зменшення коливань затримки на 95% |
Замінюючи випадкові припущення строгим математичним обліком конвеєра та одночасним усуненням пропусків, RFC 6675 забезпечує стійку роботу зашифрованих тунелів VPN у динамічних бездротових мережах. У складі сучасного мережевого стека алгоритм SACK є надійною основою швидкого зв'язку без затримок для бізнесу.



