Оверлейные сети VXLAN в Linux

Недавно мы писали о выпуске первого релиза расширения для CloudStack, позволяющего выделять дополнительные частные сети, организуемые посредством оверлейных сетей VXLAN. При разработке расширения нам очень помог блог Vincent Bernat из Exoscale. Сегодня мы подробнее остановимся на конфигурировании VXLAN в Linux.

Данная статья является адаптированным и дополненным переводом англоязычной статьи автора Vincent Bernat. В статье вы встретите ссылки и на другие статьи автора.

VXLAN (Virtual eXtensible Local Area Network) – оверлейная сеть для передачи трафика Ethernet по существующей (высокодоступной и масштабируемой) IP-сети при одновременном размещении большого числа групп пользователей. Данное определение представлено в RFC 7348. VXLAN вполне реализованы в Linux, начиная с версии 3.12 поддерживаются мультивещание (multicast) и одноадресная передача (unicast), а также IPv6 и IPv4. Традиционно VXLAN работают с использованием групп мультивещания, но не всегда они применимы. В этой статье мы рассмотрим различные методы настройки сети VXLAN в Linux, и более подробно остановимся на вариантах применения одноадресной передачи (unicast).

Термин “оверлейная” означает, что VXLAN создает логические сети поверх физических, а именно, логические сети L2 поверх IP сети. VXLAN обладает ключевыми чертами оверлейной сети:

  • Связь обычно устанавливается между двумя конечными точками туннеля (VXLAN Tunnel Endpoints или VTEP).
  • VXLAN инкапсулирует оригинальные пакеты в новый заголовок. Например, IPSec VPN, оверлейная технология, инкапсулирует оригинальный IP-кадр в IP-заголовок.

Позднее мы вернемся к инкапсуляции. А пока рассмотрим способы конфигурации VXLAN. На рисунке ниже представлен пример развертывания VXLAN:

Для иллюстрации примеров будем использовать следующие настройки:

  • транспортная IP сеть (высокодоступная и масштабируемая, возможно, Интернет),
  • три моста Linux в качестве VTEP,
  • четыре сервера, предположительно находящиеся в общем сегменте Ethernet.

Туннель VXLAN распределяет отдельные сегменты Ethernet по трем мостам, предоставляя единый виртуальный сегмент Ethernet, в котором с одного хоста (например, H1) можно напрямую связаться со всеми остальными хостами.

$ ping -c10 -w1 -t1 ff02::1%eth0
PING ff02::1%eth0(ff02::1%eth0) 56 data bytes
64 bytes from fe80::5254:33ff:fe00:8%eth0: icmp_seq=1 ttl=64 time=0.016 ms
64 bytes from fe80::5254:33ff:fe00:b%eth0: icmp_seq=1 ttl=64 time=4.98 ms (DUP!)
64 bytes from fe80::5254:33ff:fe00:9%eth0: icmp_seq=1 ttl=64 time=4.99 ms (DUP!)
64 bytes from fe80::5254:33ff:fe00:a%eth0: icmp_seq=1 ttl=64 time=4.99 ms (DUP!)

--- ff02::1%eth0 ping statistics ---
1 packets transmitted, 1 received, +3 duplicates, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.016/3.745/4.991/2.152 ms

Стандартная настройка VXLAN

При стандартном развертывании VXLAN использует IP-группу мультивещания для соединения c другими VTEP:

# ip -6 link add vxlan100 type vxlan \
    id 100 \
    dstport 4789 \
    local 2001:db8:1::1 \
    group ff05::100 \
    dev eth0 \
    ttl 5
# brctl addbr br100
# brctl addif br100 vxlan100
# brctl addif br100 vnet22
# brctl addif br100 vnet25
# brctl stp br100 off
# ip link set up dev br100
# ip link set up dev vxlan100

Команды выше создают новый интерфейс, выступающий в качестве конечной точки туннеля VXLAN vxlan100, и помещают его в мост с обычными интерфейсами.

Это один из возможных вариантов реализации. Мост необходим только в случае, если необходимо присоединение локальных интерфейсов к VXLAN. Другой стратегией является применение интерфейсов MACVLAN.

Каждый сегмент VXLAN связан с 24-битным ID, VXLAN Network Identifier или VNI. В нашем примере, в качестве VNI по умолчанию указан id 100.

Когда VXLAN была впервые реализована в Linux 3.7, UDP порт, который нужно использовать, не был определен. Несколько вендоров использовали 8472, и Linux стал использовать то же значение. Чтобы не нарушать уже существующие конфигурации, это значение используется по умолчанию. Поэтому, если вы хотите использовать порт, назначенный IANA, необходимо точно указать его с помощьюdstport 4789.

Так как мы будем использовать multicast, необходимо указать группу мультивещания (group ff05::100), а также физическое устройство (dev eth0). При использовании multicast значение TTL по умолчанию равно 1. Если ваша сеть мультивещания использует какую-либо маршрутизацию, то значение следует немного увеличить, наример, как указано в примере выше, ttl 5.

Устройство vxlan100 выполняет функцию транспортного устройства для моста с удаленными VTEP в качестве виртуальных портов:

  • оно рассылает широковещательные, одноадресные и многоадресные (BUM) кадры всем VTEP, используя группу мультивещания, и
  • оно обнаруживает связь MAC-адресов Ethernet с IP-адресами VTEP, используя изучение адресов источников кадров.

На рисунке ниже изображена общая конфигурация с использованием базы MAC (FDB, Forwarding Database) моста Linux (с изучением локальных МАС-адресов) и FDB устройства VXLAN (с изучением удаленных МАС-адресов):

Посмотреть содержимое FDB на устройстве VXLAN можно с помощью команды bridge. Если MAC-адрес назначения существует, кадр посылается связанному с ним VTEP (одноадресная сеть). Нулевой адрес используется только тогда, когда МАС-адрес назначения не найден.

# bridge fdb show dev vxlan100 | grep dst
00:00:00:00:00:00 dst ff05::100 via eth0 self permanent
50:54:33:00:00:0b dst 2001:db8:3::1 self
50:54:33:00:00:08 dst 2001:db8:1::1 self

Больше информации о настройке сети мультивещания и построении сегментов VXLAN над ней вы найдете в статье.

Реализация без поддержки multicast

Использование VXLAN в IP-сети мультивещания имеет ряд преимуществ:

  • автоматическое обрнаружение других VTEP внутри одной группы мультивещания,
  • хорошее использование полосы пропускания (репликация пакетов происходит как можно позднее),
  • дизайн, отличающийся децентрализованностью и не требующий управления.

Базовая сеть мультивещания может все же нуждаться в некоторых центральных компонентах, таких как точки rendez-vous для протокола PIM-SM. К счастью, их можно сделать высокодоступными и масштабируемыми (например, с помощью Anycast-RP, RFC 4610).

Однако, multicast не всегда доступен, а управлять им при масштабировании может быть сложно. В Linux 3.8, к реализации VXLAN добавлены расширения DOVE, что устраняет необходимость использования multicast.

Одноадресная передача со статической лавинной рассылкой (flooding)

Мультивещание можно заменить на реплицирование кадров BUM в статически сконфигурированный список удаленных VTEP:

# ip -6 link add vxlan100 type vxlan \
    id 100 \
    dstport 4789 \
    local 2001:db8:1::1
    
# bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 2001:db8:2::1
# bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 2001:db8:3::1

Для этого и последующих примеров необходим патч для команды ip (он будет включен в версию 4.11), чтобы использовать IPv6 для передачи данных. На данный момент используйте следующий обходной путь:

# ip -6 link add vxlan100 type vxlan \
>   id 100 \
>   dstport 4789 \
>   local 2001:db8:1::1 \
>   remote 2001:db8:2::1

# bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 2001:db8:3::1

VXLAN определяется без удаленной группы мультивещания. Вместо этого все удаленные VTEP связываются с нулевым адресом: кадр BUM будет дублироваться на все удаленные точки. Устройство VXLAN автоматически запомнит удаленные адреса посредством изучения адресов источников кадров.

Это решение очень простое. Применив небольшую автоматизацию, можно легко поддерживать актуальность записей по умолчанию в FDB. Однако, хост должен будет дублировать каждый кадр BUM (head-end replication) на все удаленные VTEP. Это допустимо, если их десяток. Сложнее, если их тысячи.

Примером использования данной стратегии (head-end replication) является Cumulus vxfld daemon.

Одноадресная передача со статическими записями L2

Зная связи MAC-адресов с VTEP, можно предконфигурировать FDB и отключить изучение адресов источников:

# ip -6 link add vxlan100 type vxlan \
    id 100 \
    dstport 4789 \
    local 2001:db8:1::1 \
    nolearning
    
# bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 2001:db8:2::1
# bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 2001:db8:3::1
# bridge fdb append 50:54:33:00:00:09 dev vxlan100 dst 2001:db8:2::1
# bridge fdb append 50:54:33:00:00:0a dev vxlan100 dst 2001:db8:2::1
# bridge fdb append 50:54:33:00:00:0b dev vxlan100 dst 2001:db8:3::1

С помощью флага nolearning отключается изучение адресов источников. Следовательно, если MAC отсутствует, кадр всегда будет отправляться с использованием нулевых записей.

Нулевые записи необходимы для широковещательного трафика и трафика мультивещания (например, обнаружение соседей по ARP и IPv6). Этот тип настройки подходит для предоставления виртуальным машинам виртуальных сетей L2 (когда информация L3 недоступна). Для обновления записей FDB понадобятся какие-то связанные записи.

Примерами использования данной стратегии можно назвать BGP EVPN и Cumulus Quagga (см. подробнее статью).

Одноадресная передача со статическими записями L3

В предыдущем примере нам приходилось сохранять все нулевые записи для корректного обнаружения соседей по ARP и IPv6. Однако, Linux может ответить на запросы соседей от имени удаленных узлов.

Возможно, возникнет необходимость применения к ядру патча, связанного с IPv6 (появится в 4.12). Также, для работы ICMPv6 необходим дополнительный патч (появится в 4.15, представлен в 4.14.2 и 4.13.16).

При активации данной опции записи по умолчанию становятся не нужны (но их можно сохранять):

# ip -6 link add vxlan100 type vxlan \
    id 100 \
    dstport 4789 \
    local 2001:db8:1::1 \
    nolearning \
    proxy
    
# ip -6 neigh add 2001:db8:ff::11 lladdr 50:54:33:00:00:09 dev vxlan100
# ip -6 neigh add 2001:db8:ff::12 lladdr 50:54:33:00:00:0a dev vxlan100
# ip -6 neigh add 2001:db8:ff::13 lladdr 50:54:33:00:00:0b dev vxlan100

# bridge fdb append 50:54:33:00:00:09 dev vxlan100 dst 2001:db8:2::1
# bridge fdb append 50:54:33:00:00:0a dev vxlan100 dst 2001:db8:2::1
# bridge fdb append 50:54:33:00:00:0b dev vxlan100 dst 2001:db8:3::1

Данная настройка полностью исключает head-end replication. Однако, также не будут работать и протоколы, основанные на мультвещании. При применении некоторой автоматизации эта настройка должна хорошо работать с контейнерами: если в реестре хранится список всех используемых IP и MAC-адресов, программа может слушать его и настраивать FDB и соседние таблицы.

Примером использования данной стратегии является бэкенд VXLAN в Docker libnetwork, но в нем также используется и метод, представленный далее.

Одноадресная передача с динамическими записями L3

Linux также может уведомлять программу в случае отсутствия записи (L2 или L3). Программа обращается к некоему центральному реестру и динамически добавляет запрашиваемую запись. Однако, для записей L2 отправка уведомлений используется только в случаях, когда:

  • MAC-адрес назначения неизвестен,
  • в FDB нет нулевой записи,
  • MAC-адрес назначения не является многоадресным или широковещательным.

Данные ограничения не позволяют применить сценарий “одноадресной передачи с динамическими записями L2”.

Сперва создадим устройство VXLAN с опциями 12miss и 13miss:

ip -6 link add vxlan100 type vxlan \
   id 100 \
   dstport 4789 \
   local 2001:db8:1::1 \
   nolearning \
   l2miss \
   l3miss \
   proxy

Возможно, возникнет необходимость применения патча для IPv6 к ядру (появится в 4.12) для получения соответствующих уведомлений для отсутствующих адресов IPv6.

Уведомления отправляются программам, слушающим сокет AF_NETLINK и использующим протокол NETLINK_ROUTE. Этот сокет должен быть связан с группой RTNLGRP_NEIGH. Как раз это, а также декодирование полученных уведомлений, производится с помощью:

# ip monitor neigh dev vxlan100
miss 2001:db8:ff::12 STALE
miss lladdr 50:54:33:00:00:0a STALE

Первое уведомление сообщает об отсутствии записи соседа для запрошенного IP-адреса. Ее можно добавить с помощью следующей команды:

ip -6 neigh replace 2001:db8:ff::12 \
    lladdr 50:54:33:00:00:0a \
    dev vxlan100 \
    nud reachable

Это временная запись, т.е. нам не придется ее удалять по истечении срока действия. При устаревании записи придет уведомление для ее обновления.

Когда хост получает наш ответ proxy на запрос на обнаружение соседей, он может отправить кадр с MAC-адресом, указанным нами в качестве адреса назначения. Второе уведомление касается отсутствия FDB записи для данного MAC-адреса. Мы добавляем соответствующую запись с помощью следующей команды:

bridge fdb replace 50:54:33:00:00:0a \
    dst 2001:db8:2::1 \
    dev vxlan100 dynamic

Правильнее будет добавить запись непосредственно после первого уведомления, чтобы избежать ненужных повторных передач.

Эта запись также не постоянная, иначе это могло бы помешать миграции MAC на локальный VTEP (динамическая запись не переопределяет постоянную запись).

Эта настройка хорошо работает с контейнерами и глобальным реестром. Однако, для первых подключений будет некоторое запаздывание сигнала. Более того, в транспортной сети не будут доступны мультивещание и широковещательная передача. Примером данной стратегии является бэкенд VXLAN в flannel, сетевой матрице для Kubernets.

Принятие решения

Не существует универсального решения. Можно рассматривать применение мультивещания, если:

  • оно доступна в вашей среде,
  • вы готовы разработать (и масштабировать) сеть мультивещания,
  • внутри виртуальных сегментов необходимы мультивещание и широковещательная передача,
  • у вас нет доступных адресов L2/L3.

Данное решение достаточно хорошо масштабируется, если не помещать все интерфейсы VXLAN в одну группу мультивещания (например, использовать последний байт VNI в качестве последнего байта группы).

Если нельзя использовать мультивещание, можно применить BGP EVPN: BGP используется в качестве контроллера для обеспечения распределения списка VTEP и соответствующих им FDB. Как говорилось выше, это решение используется в Cumulus Quagga. Изучению этого решения посвящена статья.

Если вы работаете в контейнероподобной среде, где заранее известны адреса L2/L3, подойдет решение с использованием статических и/или динамических записей L2 и L3 на основе центрального реестра без изучения адресов источников. Оно обеспечит бОльшую безопасность благодаря связанным ресурсам, ослаблению атак MiTM, невозможности усилить использование пропускной способности через избыточную передачу.

В зависимости от специфики окружения можно применять различные решения. Выше уже упоминались flannel и Docker libnetwork, использующие VXLAN на бэкенде. Также, интересным является эксперимент BaGPipe BGP для Kubernetes, который использует BGP EVPN и поэтому совместим с другими вендорами. Если ни одно из готовых решений не подходит под специфику вашей разработки, можно создать свой собственный вариант реализации. В этом случае может быть полезна представленная ниже информация.

Другие факторы, которые необходимо учесть

Независимо от выбранной стратегии, есть несколько важных аспектов, которые необходимо учесть при применении оверлейной сети VXLAN.

Изоляция

Вы можете ожидать, что интерфейсы VXLAN будут передавать только трафик L2. Но Linux не отключает обработку IP-адресов. Если MAC-адрес назначения является локальным, Linux будет маршрутизировать или доставлять инкапсулированный IP-пакет. См. подробнее статью о правильной изоляции моста Linux.

Шифрование

VXLAN обеспечивает изоляцию между пользователями, но трафик остается полностью незашифрован. Наиболее явным решением для шифрования является использование IPsec. Некоторые решения на основе контейнеров могут поддерживать IPsec из коробки (в частности, Docker libnetwork, flannel также планирует реализовать поддержку IPsec). Это особенно важно при развертывании через публичное облако.

Служебные данные

Инкапсулированный в VXLAN кадр имеет следующий формат:

VXLAN добавляет фиксированный размер служебных данных 50 байт. Если используется IPsec, размер служебных данных зависит от многих факторов. В транспортном режиме с AES и SHA256 служебные данные составляют 56 байт. При прохождении NAT это 64 байта (дополнительный UDP-заголовок). В туннельном режиме это 72 байта.

Некоторые пользователи ожидают, что смогут использовать Ethernet MTU 1500 для оверлейной сети. Следовательно, необходимо увеличить MTU транспортной сети. Если это невозможно, убедитесь, что внутренний MTU (внутри контейнеров или виртуальных машин) достаточно уменьшен.

В сегменте Ethernet не существует такого понятия, как обнаружение MTU.

IPv6

Хотя во всех перечисленных выше примерах используется IPv6, экосистема еще не достаточно готова. Сценарий мультивещания L2 хорошо работает с IPv6, но любой другой сценарий на данный момент требует дополнительных патчей (1, 2, 3).

Более того, IPv6, не был реализован в инструментах, связанных с VXLAN:

Multicast

Реализация Linux VXLAN не поддерживает отслеживание IGMP. Если в FDB не будут добавлены MAC-адреса, трафик мультивещания будет транслироваться на все VTEP.

Заключение

В отличие от VLAN, VXLAN дает возможность создавать и поддерживать гораздо большее количество виртуальных сетей. Построение с помощью VXLAN виртуальных сетей поверх IP-сетей (L3) обеспечивает связность L2 вне зависимости от физического расположения узлов. Также, важна гибкость сетевых инфраструктур, в том числе за счет упрощения процесса их настройки и переконфигурирования. Все эти преимущества объясняют популярность использования VXLAN в сфере виртуализации ресурсов. Представленные в статье варианты конфигурации VXLAN не охватывают все варианты применения, но раскрывают важные аспекты, на которые следует обратить внимание при выборе готового решения или разработке собственного решения, отвечающего вашим требованиям.

Если вам понравился этот пост, поделитесь им с друзьями.