понедельник, 9 января 2017 г.

Новая реализация fastfwd в FreeBSD 11

Не так давно я смержил в stable/11 обновлённую реализацию fastfwd из head/. А сегодня подошло время MFC аналогичной реализации для IPv6. Для тех кто не знает, поясню чем отличается fastfwd от обычной маршрутизации. До выхода 11-ой версии в FreeBSD было две sysctl переменных, управляющих поведением маршрутизатора: net.inet.ip.forwarding и net.inet.ip.fastforwarding. Первая включает собственно обычную маршрутизацию, т.е. пересылку входящих IPv4 пакетов, которые адресованы других хостам. Вторая - включает использование упрощённого варианта, который выполняет меньшее количество действий и не поддерживает IPsec.

Как это реализовано внутри: входящий пакет после обработки канальным уровнем (например, Ethernet) ставится в очередь обработки IP (netisr queue). Далее эта очередь обрабатывается стеком IP - функцией ip_input(). К пакету применяется ряд проверок на корректность, выполняется обработка пакетными фильтрами (на интерфейсе получения), затем определяется необходимость выполнить пересылку (т.к. пакет адресован не нам). После этого пакет передаётся в функцию маршрутизации ip_forward(). Тут у пакета уменьшается TTL, проверяется необходимость применения IPsec преобразований, выполняется поиск маршрута до адреса назначения и пакет передаётся в функцию отправки ip_output(). Здесь опять же выполняется ряд проверок, пакет передаётся на обработку пакетным фильтрам (уже на интерфейсе отправления); выполняется фрагментация, если нужно. И в конце концов пакет отправляется в канальный уровень, где после добавления Ethernet заголовка он передаётся в драйвер сетевой карты.

Вот такая, довольно громоздкая цепочка действий, в случае с включённым режимом fastforwarding, упрощается до следующих действий: входящий пакет сразу из канального уровня передаётся в функцию ip_fastforward(), где выполняются базовые проверки корректности; пакет обрабатывается пакетными фильтрами на интерфейсе получения; находится необходимый маршрут; уменьшается TTL и выполняется обработка пакетными фильтрами на интерфейсе отправления; после чего пакет сразу отправляется в канальный уровень (если нужна фрагментация, она делается тут же).

За счёт уменьшения числа действий и прямого исполнения без использования очередей netisr в итоге этот вариант получает довольно заметный прирост в производительности. Особенно если исключить из этих действий ещё и пакетные фильтры. На многоядерных процессорах и при использовании сетевых карт с несколькими очередями обработки fastfwd получает ещё более заметный прирост.

В FreeBSD 11 режим fastforwarding стал использоваться по-умолчанию. Последовательность обработки немного отличается от того, что описано выше, но принцип получения прироста производительности в общем-то сохранился.

С увеличением числа процессорных ядер и обрабатываемых пакетов в единицу времени на первый план вышла другая проблема. Теперь несколько одновременно выполняемых потоков борются за доступ к общим ресурсам. Например, при маршрутизации в несколько потоков каждый поток хочет получить эксклюзивный доступ к записи в таблице маршрутизации. Что приводит к простою в ожидании доступа. В результате  общая производительность может даже ухудшиться.

Старый API, используемый для поиска маршрута, обладает таким недостатком. Поэтому обновлённая реализация использует API, который основан на наработках проекта projects/routing. Вот несколько графиков, демонстрирующих изменения в производительности от использования нового API на различном железе:

Тесты и графики построены автором проекта BSD Router Project Olivier Cochard-Labbé. Для IPv6 графиков не нашёл, но тоже можно ожидать примерно такого же роста. Ещё интересный график влияния изменений в FreeBSD CURRENT на производительность маршрутизации за 2016 год:


Комментариев нет:

Отправить комментарий