Зачем 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
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:
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