# VLAN и trunk - 802.1Q _Сеть: L2 / L3 · LinuxLab Knowledge Base_ **TL;DR:** VLAN - логическое разделение одного физического свитча на несколько L2. Tag 802.1Q добавляет 4 байта в Ethernet-frame с VLAN-ID (12 бит, до 4094 VLAN). Trunk = много VLAN на порте, access = один. ## Зачем VLAN Физический свитч - один [[broadcast-domain|broadcast-домен]]. Все хосты слышат друг друга, ARP-broadcasts шумят, нет изоляции трафика. Если бухгалтерии нельзя видеть DMZ - физически нужно два свитча. VLAN решает это **виртуально**: один свитч ведёт себя как несколько независимых. Хосты в разных VLAN не видят друг друга на L2 - взаимодействие только через [[default-gateway|роутер]] (inter-VLAN routing). ## 802.1Q - tagged frame Стандартный [[ethernet-frame|Ethernet-frame]] имеет: ``` | dst-MAC | src-MAC | EtherType | payload | FCS | ``` 802.1Q вставляет **4 байта тега** между src-MAC и EtherType: ``` | dst-MAC | src-MAC | 0x8100 | TCI | EtherType | payload | FCS | ``` - **0x8100** - сигнал «дальше тег 802.1Q» - **TCI** (Tag Control Information): - **PCP** (3 бита) - QoS приоритет 0-7 - **DEI** (1 бит) - drop eligible - **VID** (12 бит) - **VLAN-ID, 0-4095** (0 и 4095 зарезервированы) ## Access vs Trunk Свитч-порт работает в одном из режимов: - **Access port** - порт «принадлежит» одному VLAN. Frame от хоста идёт в свитч без тега - свитч добавляет тег внутри. Frame наружу к хосту - тег снимается. Хост не знает про VLAN. - **Trunk port** - порт несёт **несколько VLAN**. Frame идёт с тегом 802.1Q. Используется между свитчами или к хост-машине, которая сама разбирает теги (виртуализация, контейнеры). ``` VLAN 10 VLAN 20 VLAN 10 | | | |access |access |access [SW1] ─── trunk ─── [SW2] (10,20) ``` ## Native VLAN На trunk-порте может быть **untagged-VLAN**: frame без тега считается принадлежащим этому VLAN. По дефолту = VLAN 1. Это **источник багов и атак** (VLAN-hopping). Лучшая практика: - Native VLAN явно прописать (не оставлять дефолт) - Не использовать VLAN 1 для пользовательского трафика - На trunk'е лучше делать всё tagged ## VLAN на Linux ### Sub-interface через ip link ```bash ip link add link eth0 name eth0.10 type vlan id 10 ip addr add 10.10.0.1/24 dev eth0.10 ip link set eth0.10 up ``` Получаем суб-интерфейс `eth0.10` который шлёт всё с тегом VLAN 10. ### Современный - vlan-aware bridge В Docker/Kubernetes/libvirt используют **bridge** с поддержкой VLAN: ```bash ip link add br0 type bridge vlan_filtering 1 bridge vlan add dev eth0 vid 10 pvid 10 untagged # access bridge vlan add dev eth1 vid 10 tagged # trunk bridge vlan add dev eth1 vid 20 tagged ``` Один [[bridge|bridge]] эмулирует свитч с access и trunk-портами. ## Inter-VLAN routing Хосты в VLAN 10 и 20 на L2 не видят друг друга. Чтобы общаться - нужен L3-маршрут. Делается через **router-on-a-stick**: один физический интерфейс роутера, два суб-интерфейса с тегами 10 и 20, у каждого свой IP - один = шлюз для VLAN10, второй = шлюз для VLAN20: ``` router# show ip route 10.10.0.0/24 → eth0.10 10.20.0.0/24 → eth0.20 ``` Хосты в VLAN10 ставят default gateway = IP суб-интерфейса в VLAN10. ## QinQ (двойной тег) - 802.1ad Когда VLAN-теги нужно прокидывать через провайдера, у которого свои VLAN, делают **двойную инкапсуляцию**: ставят S-tag (service VLAN провайдера) поверх C-tag (customer VLAN). EtherType = 0x88a8. Ограниченно поддерживается на Linux: `vlan_protocol 802.1ad`. ## Когда что-то пошло не так - **Не пингует через trunk** - native VLAN не совпадает на двух свитчах, либо порт не в trunk-режиме (access по дефолту) - **VLAN drop'ается** - проверь что MTU на trunk-порте ≥ 1504 (1500 payload + 4 байта тега) - **VLAN-hopping атака** - native VLAN угадан, нападающий шлёт double-tagged. Защита: tagged native, отключить DTP (auto-trunk) - **Хост получает чужой broadcast** - svc-порт настроен в неверном VLAN - **Проблемы с jumbo frames + VLAN** - MTU должен учитывать тег; 9000 jumbo на access, 9004 на trunk ## Команды ```bash sudo ip link add link eth0 name eth0.10 type vlan id 10 ``` Создать VLAN-интерфейс 10 на eth0; нужен модуль ядра 8021q ```bash ip -d link show eth0.10 ``` -d показывает детали - vlan id, protocol (802.1q vs 802.1ad) ```bash bridge vlan show ``` Все VLAN на vlan-aware bridge портах: untagged/tagged ```bash tcpdump -i eth0 -nne 'vlan' ``` Отфильтровать только tagged frames - сразу видно ID и payload ```bash lsmod | grep 8021q ``` Загружен ли модуль 8021q. Если нет: sudo modprobe 8021q ## См. также - [Ethernet frame](/kb/ethernet-frame.md) - [Broadcast-домен - что это и кто в нём живёт](/kb/broadcast-domain.md) - [VXLAN - L2 overlay поверх L3-сети](/kb/vxlan-overlay.md) - [Bonding и teaming - объединение интерфейсов](/kb/bonding-and-teaming.md) - [Default gateway - выход из своей сети](/kb/default-gateway.md) - [CNI plugins - сеть Kubernetes (calico, cilium, flannel)](/kb/cni-plugins.md)