Что такое VRF и зачем он нужен в Linux
VRF (Virtual Routing and Forwarding) - это технология виртуализации маршрутизации на уровне L3. Она создает несколько независимых экземпляров таблиц маршрутизации в одном ядре Linux. Каждый VRF-домен оперирует собственным набором маршрутов и правил, полностью изолированным от глобальной таблицы и других доменов. Трафик, попавший в VRF, никогда не пересечется с трафиком другого домена на одном физическом интерфейсе.
Главное отличие от VLAN - уровень изоляции. VLAN тегирует кадры на L2 и требует настройки коммутаторов, транков и сабинтерфейсов. VRF изолирует трафик на L3 без изменения L2-заголовков. Это упрощает архитектуру: вам не нужно поднимать виртуальные интерфейсы для каждой подсети или настраивать тегирование на соседнем оборудовании. Еще одно преимущество - возможность использовать перекрывающиеся IP-адреса в разных VRF. Два клиента могут иметь одинаковую адресацию 192.168.1.0/24 без конфликтов, потому что их таблицы маршрутизации изолированы.
VRF решает конкретные задачи в корпоративных сетях и ЦОД. Первый сценарий - изоляция клиентов в мультитенантной среде. Каждый арендатор получает собственный VRF-домен с независимой маршрутизацией. Второй - разделение трафика управления и данных на одном сервере. Интерфейс управления живет в одном VRF, продуктовый трафик - в другом. Третий - тестовые среды, которые не должны влиять на продакшен. Четвертый - принудительная маршрутизация трафика конкретных приложений через VPN-туннели без вмешательства в глобальную таблицу. Если вы работали с VRF на Cisco Nexus, логика будет знакомой, но реализация в Linux имеет свою специфику.
Подготовка системы и проверка поддержки VRF
VRF поддерживается ядром Linux начиная с версии 4.8. Полноценная стабильная работа гарантируется с ядра 4.15 и выше. Рекомендую использовать ядро 5.x или 6.x - в них исправлены критические ошибки, связанные с обработкой сокетов и работой IPv6 внутри VRF. Проверьте версию ядра командой:
uname -r
Далее убедитесь, что модуль vrf доступен системе. Выполните загрузку модуля и проверку:
modprobe vrf
modinfo vrf
Если команды отработали без ошибок - поддержка на уровне ядра есть. Следующий шаг - пакет iproute2. Именно утилита ip из этого пакета управляет VRF. Минимальная версия - 4.8, но актуальные дистрибутивы (Debian 11+, Ubuntu 22.04+, RHEL 9+) содержат всё необходимое из коробки. Проверьте версию:
ip -V
Для автоматизации через systemd потребуется версия менеджера не ниже 237. Эта версия поддерживает директиву NetworkNamespacePath, которая понадобится для запуска сервисов в VRF. Проверьте:
systemctl --version
Создание VRF-домена и привязка интерфейса
Создание VRF выполняется одной командой. Вы указываете имя домена и номер таблицы маршрутизации, которая будет ассоциирована с этим VRF. Номер таблицы - произвольное целое число от 1 до 4294967295. Рекомендую использовать значения из диапазона 100-1000, чтобы не пересекаться с системными таблицами:
ip link add vrf-blue type vrf table 10
После создания домен нужно поднять, как обычный интерфейс:
ip link set vrf-blue up
Теперь привяжите физический интерфейс к VRF. Интерфейс становится «рабом» VRF-мастера и теряет глобальную видимость - его IP-адреса и маршруты перемещаются в таблицу VRF:
ip link set eth1 master vrf-blue
Проверьте результат:
ip vrf show
Вывод покажет имя VRF и связанную с ним таблицу. Команда ip link show отобразит интерфейс eth1 с флагом master vrf-blue. Важный момент: IP-адрес интерфейса нужно назначить заново после привязки к VRF, если он был настроен ранее. Глобальный адрес слетает при смене мастера:
ip addr add 192.168.1.10/24 dev eth1
Настройка маршрутов внутри VRF
Маршруты добавляются с указанием имени VRF. Они попадают в изолированную таблицу и не видны в глобальной:
ip route add vrf vrf-blue default via 192.168.1.1
ip route add vrf vrf-blue 10.0.0.0/8 via 192.168.1.254
Просмотр таблицы конкретного VRF:
ip route show vrf vrf-blue
Глобальная команда ip route show не покажет этих маршрутов. В этом и заключается изоляция - процесс, привязанный к VRF, использует только свою таблицу. Соседние VRF и основная система о ней не знают.
Настройка правил IP-правил (ip rule) для VRF
При добавлении интерфейса в VRF ядро автоматически создает правила маршрутизации. Они привязывают трафик, приходящий с этого интерфейса, к таблице VRF. Просмотрите правила:
ip rule show
Вы увидите записи вида:
1000: from all lookup [l3mdev-table]
2000: from all lookup [l3mdev-table] unreachable
Приоритет 1000 означает, что трафик, приходящий на интерфейс-раб VRF, сначала ищет маршрут в таблице этого VRF. Если маршрут не найден, пакет уходит в unreachable, а не в глобальную таблицу. Это гарантирует изоляцию - трафик не может «провалиться» в основную систему.
Для специфических сценариев можно создать ручные правила. Например, направить трафик от определенного исходного адреса в VRF:
ip rule add from 192.168.1.100 table 10 priority 500
Этот метод близок к Policy-Based Routing в Linux, но VRF дает более жесткую изоляцию на уровне устройств, а не только маршрутов.
Привязка процессов к VRF
Запуск процесса в изолированном сетевом контексте выполняется утилитой ip vrf exec. Все сокеты, которые откроет процесс, будут привязаны к указанному VRF-домену. Проверьте работу на примере ping:
ip vrf exec vrf-blue ping 8.8.8.8
Пакеты пойдут через таблицу маршрутизации vrf-blue, используя шлюз по умолчанию этого домена. Трассировка также работает:
ip vrf exec vrf-blue traceroute 8.8.8.8
Механизм работает через привязку сокетов к сетевому устройству VRF с помощью SO_BINDTODEVICE. Это накладывает ограничение: не все приложения корректно обрабатывают такую привязку. Старые версии Nginx, некоторые VPN-клиенты и самописные утилиты, которые игнорируют SO_BINDTODEVICE, могут выходить в глобальную сеть в обход VRF. Перед внедрением в продакшен обязательно тестируйте целевое приложение.
Автоматизация через systemd
Для продакшен-сред процесс должен стартовать в VRF автоматически. Systemd предоставляет два способа. Первый - использование ip vrf exec в ExecStart:
[Unit]
Description=My Service in VRF Blue
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/bin/ip vrf exec vrf-blue /usr/bin/my-app --config /etc/my-app.conf
Restart=always
[Install]
WantedBy=multi-user.target
Второй способ - директива NetworkNamespacePath. Она указывает путь к сетевому пространству имен VRF. Этот метод предпочтительнее, так как не зависит от внешней утилиты:
[Service]
NetworkNamespacePath=/var/run/netns/vrf-blue
ExecStart=/usr/bin/my-app --config /etc/my-app.conf
Пространство имен для VRF создается автоматически при поднятии домена. Убедитесь, что сервис стартует после настройки сети - используйте After=network-online.target и Wants=network-online.target. Без этого приложение может запуститься до готовности VRF и не получить сетевой доступ.
Интеграция VRF с Docker-контейнерами
Docker не имеет нативной интеграции с VRF, но это решается двумя подходами. Первый - запуск демона Docker целиком внутри VRF. Все контейнеры на этом хосте будут изолированы в одном домене. Способ грубый, подходит для выделенных сред. Второй подход - выборочная привязка контейнеров через macvlan-сети, поднятые поверх VRF-интерфейса. Он дает гибкость: контейнеры разных клиентов живут в разных VRF на одном хосте.
Создайте macvlan-интерфейс поверх интерфейса, который уже привязан к VRF:
ip link add macvlan-blue link eth1 type macvlan mode bridge
ip link set macvlan-blue master vrf-blue
ip addr add 192.168.1.100/24 dev macvlan-blue
ip link set macvlan-blue up
Теперь создайте Docker-сеть с драйвером macvlan, указав родительский интерфейс:
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=macvlan-blue \
net-blue
Запустите контейнер в этой сети:
docker run -d --network net-blue --name app-blue nginx
Контейнер получит IP из подсети VRF и будет маршрутизироваться через таблицу vrf-blue. Для проверки изоляции запустите второй контейнер в другом VRF и убедитесь, что они не видят друг друга на сетевом уровне.
Пример: изоляция контейнеров двух клиентов
Задача: на одном сервере размещены контейнеры клиентов A и B. Оба используют подсеть 192.168.1.0/24, но их трафик должен быть полностью изолирован. Решение - два VRF и два macvlan-интерфейса.
Создайте VRF и macvlan для клиента A:
ip link add vrf-client-a type vrf table 20
ip link set vrf-client-a up
ip link add macvlan-a link eth1 type macvlan mode bridge
ip link set macvlan-a master vrf-client-a
ip addr add 192.168.1.1/24 dev macvlan-a
ip link set macvlan-a up
ip route add vrf vrf-client-a default via 192.168.1.254
Повторите для клиента B с таблицей 30 и адресом 192.168.1.1/24 на macvlan-b. Адреса совпадают, но конфликта нет - они в разных VRF. Создайте Docker-сети:
docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.254 -o parent=macvlan-a net-a
docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.254 -o parent=macvlan-b net-b
Запустите контейнеры:
docker run -d --network net-a --name client-a-app nginx
docker run -d --network net-b --name client-b-app nginx
Контейнер client-a-app и client-b-app имеют адреса из одной подсети, но полностью изолированы. Трафик каждого уходит через свой VRF со своим шлюзом. Если вы используете облачную инфраструктуру для таких сценариев, Timeweb Cloud предоставляет VDS с гибкой настройкой сети, где VRF разворачивается без ограничений гипервизора.
Проверка изоляции и диагностика
После настройки проверьте изоляцию систематически. Первый шаг - инспекция таблиц маршрутизации. Убедитесь, что маршруты VRF не просочились в глобальную таблицу:
ip route show table 10
ip route show
Второй шаг - проверка правил:
ip rule show | grep l3mdev
Правила должны присутствовать для каждого VRF. Третий шаг - тест связности изнутри VRF и снаружи:
ip vrf exec vrf-blue ping 192.168.1.1
ping -I eth1 192.168.1.1
Первая команда должна работать, вторая - нет, потому что eth1 привязан к VRF и глобальный стек его не видит. Четвертый шаг - проверка изоляции между VRF. Запустите ping из одного домена на адрес интерфейса другого домена. Ответа быть не должно.
Частые ошибки: отсутствие IP-адреса на интерфейсе после привязки к VRF (назначьте заново), неправильный шлюз по умолчанию (проверьте через ip route show vrf <name>), конфликт приоритетов в ip rule (проверьте номера правил). Для сложных случаев используйте tcpdump -i eth1 - он покажет, уходят ли пакеты с интерфейса и приходят ли ответы.
Типовые сценарии использования VRF в ЦОД
Сценарий 1 - изоляция трафика управления и данных. Сервер имеет два физических интерфейса: eth0 для управления (SSH, мониторинг) и eth1 для данных (трафик приложений). Создайте два VRF, привяжите интерфейсы и настройте независимые шлюзы. Трафик управления никогда не смешается с данными, даже при ошибке маршрутизации.
Сценарий 2 - мультитенантная среда с перекрывающимися адресами. Три клиента используют одинаковую адресацию 10.0.0.0/8. Каждому клиенту - свой VRF и macvlan-интерфейс. Адреса не конфликтуют, трафик изолирован. Этот подход часто применяется в программных маршрутизаторах на Linux, где VRF дополняет BGP и OSPF для сегментации клиентов.
Сценарий 3 - тестовая среда, изолированная от продакшена. Разработчики получают VRF с доступом только к тестовым подсетям. Ошибка в конфигурации приложения не затронет продуктовый трафик. Настройка сводится к созданию VRF, привязке тестового интерфейса и добавлению маршрутов только в тестовые сети.
Ограничения и подводные камни
VRF в Linux - зрелая технология, но с ограничениями. Минимальная версия ядра - 4.8, полная поддержка IPv6 и стабильная работа сокетов начинается с 4.15. На ядрах 4.x возможны проблемы с привязкой сокетов, когда приложение игнорирует VRF и выходит через глобальную таблицу. Перед развертыванием проверьте целевое приложение командой ip vrf exec vrf-test <app> и убедитесь, что трафик идет через нужный интерфейс.
Не все приложения совместимы. Nginx до версии 1.19 некорректно обрабатывал SO_BINDTODEVICE. Некоторые VPN-клиенты (старые версии OpenVPN, StrongSwan) привязываются к глобальному интерфейсу, игнорируя VRF. Решение - использовать сетевые пространства имен целиком или обновить ПО до актуальных версий.
Производительность. VRF работает на уровне ядра и добавляет минимальные накладные расходы - один дополнительный поиск в таблице маршрутизации. На скоростях до 10 Гбит/с влияние незаметно. При нагрузках 40 Гбит/с и выше тестируйте на конкретном железе. В наших тестах на Xeon E-2388G с ядром 6.1 падение пропускной способности составило менее 1%.
IPv6 поддерживается полностью, но требует явной настройки. Правила l3mdev-table для IPv6 создаются автоматически, однако маршруты нужно добавлять отдельно:
ip -6 route add vrf vrf-blue default via 2001:db8::1
Оркестраторы. Kubernetes не имеет нативной интеграции с VRF. Для изоляции подов используйте CNI-плагины с поддержкой Multus и macvlan, которые можно привязать к VRF-интерфейсу на уровне хоста. Это ручная настройка, требующая синхронизации конфигурации на всех нодах кластера.
Если вам нужна готовая платформа для развертывания сложных сетевых сценариев, облачные серверы Timeweb позволяют гибко настраивать сетевые интерфейсы и маршрутизацию без ограничений, типичных для shared-хостинга.