Ubuntu 24.04 міст/VLAN для віртуалізації: виправте «VM немає інтернету» правильно

Було корисно?

Ви запускаєте віртуальну машину. Вона завантажується. Отримує IP. DNS здається нормальним. І все ж: немає інтернету. ping до шлюзу таймаутить, мов він страйкує. Ви починаєте бурмотіти про «зміни в мережі Ubuntu» і «можливо образ битий», і раптом уже перезапустили libvirtd тричі — і нічого не дізналися.

Майже завжди це задача шарового рівня: неправильний дизайн моста, помилкова обробка VLAN, неправильний маршрут за замовчуванням або фаєрвол хоста тихо виконує свою роботу занадто ретельно. Виправлення — не «пробувати випадкові конфіги, поки не запрацює». Виправлення — побудувати міст/VLAN правильно, а потім перевірити як SRE: по одному хопу, в одній таблиці, з одним рішенням за раз.

Здорова ментальна модель: що має бути правдивим, щоб VM дісталася інтернету

Коли у VM «немає інтернету», спокуса трактувати це як єдину проблему велика. Це не так. Це ланцюжок умов. Пошкодьте будь-яке посилання — і ваша VM перетворюється на дуже дорогий localhost.

Негайно необхідний ланцюжок

  • Лінк у гостьовій системі активний: пристрій NIC virtio/e1000 присутній, carrier є, MAC правильний, драйвер коректний.
  • У гостьової системи правильна IP-конфігурація: IP/маска, маршрут за замовчуванням, DNS.
  • Трафік гостьової системи виходить назовні: ARP/ND працюють, пакети покидають гостевий NIC.
  • Хост коректно форвардить L2: tap/vnet інтерфейс VM прив’язаний до правильного моста; міст увімкнений і форвардить.
  • VLAN-тегування відповідає реальності: не-теговані і теговані фрейми — це саме те, що очікує upstream комутатор.
  • Хост має аплінк до реальної мережі: міст підключено до фізичної NIC (або до правильного VLAN-підінтерфейсу) з carrier.
  • Порт upstream-комутатора налаштований коректно: access чи trunk, allowed VLANs, поведінка native VLAN відома (не припускається).
  • Фаєрвол не блокує мовчки: хост nftables/iptables, libvirt-фільтри, гостьовий firewall через cloud-init або rp_filter.
  • Шлях за шлюзом працює: NAT, маршрутизація або upstream ACL дозволяють трафік.

Більшість відмов трапляється посередині: міст хоста в порядку, але VLAN-тегування неправильне; або VM підключена не до того моста; або використовується libvirt NAT, коли ви думали, що воно бриджоване.

Операційний принцип: перестаньте гадати, де помер пакет. Дивіться на кожен хоп, поки не знайдете першу точку, де реальність відрізняється від вашої моделі. Це і є виправлення.

Цікавинки та контекст (бо минуле досі є у вашій мережі)

  1. Linux-бридж існує з початку 2000-х, і він розвивався разом з віртуалізацією; KVM не винайшов потребу, він її просто індустріалізував.
  2. VLAN-тегування старше більшості «мережевих продуктів» хмар. IEEE 802.1Q з’явився наприкінці 1990-х і досі перемагає простотою: один кабель — багато мереж.
  3. За замовчуванням мережа libvirt (virbr0) — це NAT. Добре для ноутбуків, погано для «моїй VM потрібен той самий LAN, що й інші».
  4. Netplan — не мережевий демон. Це транслятор конфігурацій, який зазвичай генерує systemd-networkd на серверах (або NetworkManager на десктопах).
  5. Linux-місти можуть фільтрувати й тегувати VLAN (bridge VLAN filtering). Ви можете робити «поведінку як комутатор» у ядрі з пер-портовим членством VLAN.
  6. Spanning Tree Protocol (STP) — не лише для фізичних комутаторів. Linux-міст може брати участь, і ввімкнення STP у невідповідному місці може додати секунди «чому ніщо не проходить?» після лінк-ап.
  7. Reverse path filtering (rp_filter) спричинив більше «ping працює в один бік» інцидентів, ніж хотілося б зізнатися, особливо на багатогомових хостах.
  8. Стек мереж systemd суттєво зміцнів за останнє десятиліття. Те, що раніше потребувало ручного /etc/network/interfaces, зараз декларативне й передбачуване — якщо ви правильно задекларували.
  9. Поведінка «native» VLAN відрізняється за вендором і конфігурацією. Слово «native» — це місце, де припущення вмирають.

Також: VLAN-и схожі на організаційні схеми. Усі думають, що вони прості, поки не доведеться щось змінити.

Цитата (парафраз): Werner Vogels часто підкреслює ідею «you build it, you run it» — операційний цикл відгуку є частиною інженерії, а не додатком.

Швидкий план діагностики

Це потік «мені потрібен сигнал за п’ять хвилин». Припускає, що VM має бути бриджована до реальної мережі, опційно через VLAN.

По-перше: доведіть, що VM дійсно на тому мосту, який ви думаєте

  • Перевірте, що vnet/tap інтерфейс VM існує на хості.
  • Підтвердіть, що він підпорядкований правильному мосту (не virbr0, не якийсь сирітський міст).
  • Підтвердіть, що міст має фізичний аплінк прикріплений (або правильний VLAN-підінтерфейс).

По-друге: знайдіть перший збійний хоп зсередини VM

  • Ping до шлюзу.
  • Якщо не вдається — подивіться ARP/neighbor та захопіть трафік на інтерфейсі VM і на аплінку.
  • Якщо шлюз працює, але інтернет — ні, перевірте DNS, маршрутизацію та upstream ACL.

По-третє: перевірте очікування щодо VLAN на хості та комутаторі

  • Якщо VM не тегована, міст/аплінк має бути access/native на правильному VLAN.
  • Якщо VM тегована, або гість тегує кадри (802.1Q всередині гостя), або міст хоста застосовує теги (bridge VLAN filtering). Виберіть підхід і дотримуйтеся його.
  • Підтвердіть список дозволених VLAN на switchport; «trunk» без «allowed» — це як VLAN-и зникають.

По-четверте: виключіть фаєрвол хоста і ядрові налаштування

  • Перевірте набір правил nftables на предмет drop-правил для мостового трафіку.
  • Підтвердіть налаштування bridge netfilter; ви можете непомітно фільтрувати L2-транзит.
  • Перевірте rp_filter на хості, якщо він багатогомовий або використовується політика маршрутизації.

Якщо ви слідуєте цій послідовності, зазвичай шукаєте винуватця, ще поки ваша кава не встигла охолонути.

Практичні завдання: команди, очікуваний вивід і що ви вирішуєте далі

Це реальні операційні завдання. Виконуйте їх по порядку, поки вивід не скаже, де пакет зупиняється. Кожне завдання включає: команду(и), що означає вивід і яке рішення ви приймаєте.

Завдання 1: Визначити аплінк хоста і стан лінку

cr0x@server:~$ ip -br link
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
enp3s0           UP             3c:ec:ef:12:34:56 <BROADCAST,MULTICAST,UP,LOWER_UP>
br0              UP             3c:ec:ef:12:34:56 <BROADCAST,MULTICAST,UP,LOWER_UP>
vnet3            UP             fe:54:00:aa:bb:cc <BROADCAST,MULTICAST,UP,LOWER_UP>

Значення: enp3s0 має carrier (LOWER_UP). br0 існує і UP. Якщо ваша фізична NIC DOWN/NO-CARRIER — зупиніться тут; аплінку немає.

Рішення: Якщо аплінк down — спочатку виправте кабелі/комутатор/драйвер. Якщо аплінк up — переходьте до членства в мості.

Завдання 2: Підтвердити членство в мості (хто підключений до br0)

cr0x@server:~$ bridge link
3: enp3s0 state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> master br0
5: vnet3 state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> master br0

Значення: І фізична NIC, і VM інтерфейс vnet3 на br0. Якщо vnet3 на virbr0 або без master — VM не на цільовій мережі.

Рішення: Якщо VM не підпорядкована правильному мосту — виправте прив’язку NIC у libvirt перед тим, як лізти в VLAN або фаєрвол.

Завдання 3: Перевірити, що IP хоста знаходиться на мосту (не на фізичній NIC)

cr0x@server:~$ ip -br addr show br0 enp3s0
br0              UP             192.0.2.10/24 fe80::3eec:efff:fe12:3456/64
enp3s0           UP             fe80::3eec:efff:fe12:3456/64

Значення: IPv4-адреса хоста на br0. Це бажано для простого бриджованого дизайну. Якщо IPv4 на enp3s0, а br0 теж задіяний — ви в «може працювати, поки не зламається» зоні.

Рішення: Якщо IP хоста на неправильному інтерфейсі — виправте netplan, щоб міст мав IP.

Завдання 4: Перевірити, чи VM бачить IP, маршрут і DNS

cr0x@server:~$ virsh domifaddr vm1
 Name       MAC address          Protocol     Address
-------------------------------------------------------------------------------
 vnet3      fe:54:00:aa:bb:cc    ipv4         192.0.2.50/24

Значення: VM має IPv4-адресу. Це не доводить, що вона може дістатися до шлюзу, але доводить, що DHCP (або статичне) налаштовано.

Рішення: Якщо адреси нема — налагодьте DHCP/VLAN у гості перед тим, як звинувачувати фаєрвол хоста.

Завдання 5: З середини VM протестуйте перший хоп (шлюз) і другий хоп (публічна IP)

cr0x@server:~$ ping -c 3 192.0.2.1
PING 192.0.2.1 (192.0.2.1) 56(84) bytes of data.
64 bytes from 192.0.2.1: icmp_seq=1 ttl=64 time=0.547 ms
64 bytes from 192.0.2.1: icmp_seq=2 ttl=64 time=0.510 ms
64 bytes from 192.0.2.1: icmp_seq=3 ttl=64 time=0.522 ms

--- 192.0.2.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2040ms

cr0x@server:~$ ping -c 3 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=55 time=12.1 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=55 time=12.0 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=55 time=12.2 ms

Значення: Якщо ping до шлюзу не проходить — ви маєте справу з L2/VLAN/містом або локальним фаєрволом. Якщо шлюз працює, а публічна IP ні — це маршрутизація/NAT/upstream ACL.

Рішення: Оберіть гілку діагностики. Не шукайте DNS, якщо ви не можете протрейджити до шлюзу.

Завдання 6: Перегляньте ARP/neighbor таблицю на наявність MAC шлюзу

cr0x@server:~$ ip neigh show
192.0.2.1 dev eth0 lladdr 00:11:22:33:44:55 REACHABLE

Значення: REACHABLE з MAC означає, що ARP пройшов. Якщо INCOMPLETE/FAILED — VM кричить у порожнечу (або VLAN mismatch поглинає кадри).

Рішення: Якщо ARP incomplete — робіть capture трафіку та перевірте VLAN-теги.

Завдання 7: Захопіть трафік на vnet інтерфейсі хоста (чи VM відправляє ARP?)

cr0x@server:~$ sudo tcpdump -ni vnet3 -c 10 arp or icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on vnet3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:00:01.000000 ARP, Request who-has 192.0.2.1 tell 192.0.2.50, length 28
12:00:02.000000 ARP, Request who-has 192.0.2.1 tell 192.0.2.50, length 28

Значення: VM відправляє ARP. Якщо ви ніколи не бачите ARP тут, проблема всередині гостя (неправильний інтерфейс, down link, неправильний маршрут) або VM взагалі не підключена.

Рішення: Якщо ARP є на vnet, але немає відповіді — падіння між мостом і аплінком (VLAN, switchport або фільтрація хоста).

Завдання 8: Захопіть на аплінку хоста (чи ARP виходить з коробки?)

cr0x@server:~$ sudo tcpdump -ni enp3s0 -c 10 arp
listening on enp3s0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:00:01.000100 ARP, Request who-has 192.0.2.1 tell 192.0.2.50, length 28

Значення: Якщо ARP видно на enp3s0 — міст форвардить. Якщо бачите на vnet3, але не на enp3s0 — міст блокує або VLAN-фільтрація misconfigured.

Рішення: Якщо він не виходить з коробки — інспектуйте bridge VLAN filtering та STP-стан.

Завдання 9: Перевірте таблицю переадресації мосту (FDB) і навчання MAC

cr0x@server:~$ bridge fdb show br br0 | head
fe:54:00:aa:bb:cc dev vnet3 master br0
00:11:22:33:44:55 dev enp3s0 master br0

Значення: Міст навчив MAC VM на vnet3 і MAC шлюзу на enp3s0. Якщо MAC шлюзу ніколи не з’являється — відповіді upstream не повертаються (switchport/VLAN) або фільтруються.

Рішення: Нема навчання MAC = шукайте VLAN mismatch або STP, що блокує.

Завдання 10: Перевірте налаштування VLAN на хості (VLAN-пристрої + bridge VLAN filtering)

cr0x@server:~$ ip -d link show br0 | sed -n '1,12p'
6: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 3c:ec:ef:12:34:56 brd ff:ff:ff:ff:ff:ff
    bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 1 vlan_protocol 802.1Q

cr0x@server:~$ bridge vlan show
port              vlan-id
enp3s0             10 PVID Egress Untagged
vnet3              10 PVID Egress Untagged
br0                10 PVID Egress Untagged

Значення: vlan_filtering=1 означає, що міст веде себе як VLAN-aware комутатор. PVID 10 untagged на обох портах означає, що не-тегований трафік трактують як VLAN 10 і виходить без тегу.

Рішення: Якщо ваш switchport очікує tagged VLAN 10, а ви посилаєте untagged — виправте або switchport, або налаштування bridge VLAN. Виберіть одну правду.

Завдання 11: Перевірте netfilter/bridge налаштування, що можуть мовчки скидати мостовий трафік

cr0x@server:~$ sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.bridge.bridge-nf-call-arptables
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-arptables = 0

Значення: З bridge-nf-call-iptables=1 ваш хостовий фаєрвол може фільтрувати форвардовані мостові кадри. Це може бути нормально, але це велика причина «чому тільки VM ламаються?»

Рішення: Якщо ви покладаєтесь на nftables для безпеки хоста — тримайте це увімкненим, але переконайтеся, що правила дозволяють трафік VM. Якщо ні — вимкніть це свідомо й задокументуйте чому.

Завдання 12: Перегляньте правила nftables на наявність drop у форварді

cr0x@server:~$ sudo nft list ruleset | sed -n '1,120p'
table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    iif "lo" accept
    ct state established,related accept
    tcp dport 22 accept
  }

  chain forward {
    type filter hook forward priority filter; policy drop;
    ct state established,related accept
    iifname "br0" oifname "br0" accept
  }

  chain output {
    type filter hook output priority filter; policy accept;
  }
}

Значення: Політика drop у forward — нормально, якщо є явні дозволи. Тут, intra-bridge трафік дозволено, але трафік з br0 на enp3s0 не дозволено (бо oifname не br0). Це вб’є egress VM.

Рішення: Додайте правило, щоб дозволити пересилання br0 → аплінк (або більш точне правило по VLAN/підмережі). Не вирішуйте «policy accept» абияк — думайте.

Завдання 13: Підтвердити тип мережі libvirt (bridged vs NAT)

cr0x@server:~$ virsh domiflist vm1
 Interface   Type     Source   Model    MAC
-------------------------------------------------------
 vnet3       bridge   br0      virtio   fe:54:00:aa:bb:cc

Значення: Type=bridge Source=br0 означає, що VM дійсно бриджована. Якщо бачите Type=network Source=default — ви на libvirt NAT (virbr0).

Рішення: Якщо NAT, а ви очікували bridge — змініть джерело NIC у VM.

Завдання 14: Перевірити маршрути на хості (коли хост також ваш маршрутизатор/NAT)

cr0x@server:~$ ip route
default via 192.0.2.1 dev br0 proto dhcp src 192.0.2.10 metric 100
192.0.2.0/24 dev br0 proto kernel scope link src 192.0.2.10

Значення: Прості випадки: дефолтний маршрут хоста через LAN-шлюз. Якщо ваш дизайн використовує хост як маршрутизатор для VLANів VM — потрібна додаткова маршрутизація і IP-forwarding.

Рішення: Якщо хост має маршрутизувати між VLANами — ввімкніть ip_forward і переконайтеся в правильних зворотних маршрутах upstream.

Завдання 15: Перевірити IP forwarding і rp_filter на хості (в маршрутизуючих випадках)

cr0x@server:~$ sysctl net.ipv4.ip_forward net.ipv4.conf.all.rp_filter net.ipv4.conf.br0.rp_filter
net.ipv4.ip_forward = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.br0.rp_filter = 1

Значення: ip_forward=0 означає, що хост не маршрутизуватиме пакети. rp_filter=1 може скидати асиметричний трафік (поширено при policy routing або кількох аплінках).

Рішення: Якщо хост — маршрутизатор, увімкніть ip_forward і налаштуйте rp_filter відповідно (часто 2 для loose mode в багатогомових сценаріях).

Завдання 16: Підтвердити, що DHCP дійсно надходить з очікуваного VLAN

cr0x@server:~$ sudo tcpdump -ni enp3s0 -c 20 udp port 67 or udp port 68
listening on enp3s0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:05:01.000000 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request
12:05:01.050000 IP 192.0.2.2.67 > 192.0.2.50.68: BOOTP/DHCP, Reply

Значення: Ви бачите, що DHCP-сервер відповідає. Якщо DHCP працює, але ARP до шлюзу не вдається — можливо, ви отримуєте DHCP від relay або з іншого VLAN, ніж думаєте.

Рішення: Якщо IP DHCP-сервера вас дивує — зупиніться і узгодьте VLAN та конфігурацію switchport.

Жарт №1: DHCP — як офісна кава: коли її немає, всі раптом стають мережевими інженерами.

Правильні шаблони проектування (міст + VLAN) для хостів Ubuntu 24.04

Є три шаблони, що надійно працюють. Поганий шаблон — «трохи з кожного», бо ви копіювали снипет з трьох блогів о 2-й ночі.

Шаблон A: Нетегований міст (один VLAN / access порт)

Використовувати коли: ваш хост і VM живуть в одній мережі, а switchport — access (або trunk з відомим native VLAN, яким ви справді керуєте).

Дизайн: фізична NIC → міст br0; br0 має IP хоста; VM підключені до br0. Жодного VLAN filtering. Жодних VLAN-підінтерфейсів.

Чому це добре: менше складових. Менше шансів неправильно проставити теги. Менше суперечок з мережею.

Сценарій відмови: хтось змінює switchport на trunk або переносить вас в інший VLAN і не попереджає; ви залишаєтеся нетегованими і опиняєтесь не там.

Шаблон B: VLAN-підінтерфейс на аплінку + мости для кожного VLAN

Використовувати коли: ви хочете VM у кількох VLAN, але хочете зберегти логіку VLAN простою і явною.

Дизайн: enp3s0 — trunk на комутаторі. Створюєте VLAN інтерфейси на хості (enp3s0.10, enp3s0.20). Створюєте мости br10 і br20, кожен прикріплений до відповідного VLAN-інтерфейсу. VM підключаються до br10 або br20.

Чому це добре: дуже легко зрозуміти. Ви бачите, де теги. Також легко робити фаєрвол для кожного мосту при потребі.

Сценарій відмови: забувають дозволити VLAN на switch trunk. Або підключають VM до br0 (не того мосту) і потім лаються, що VLAN «зламаний».

Шаблон C: VLAN-aware міст з bridge VLAN filtering

Використовувати коли: ви хочете один міст, який поводиться як маленький комутатор: trunk аплінк, access порти для VM, можливо trunk для спеціальних VM, і членство VLAN контролюється на хості.

Дизайн: enp3s0 прикріплено безпосередньо до br0; br0 має vlan_filtering=1. Ви призначаєте членство VLAN на порт (enp3s0 і vnetX). VM можуть бути нетеговані (access) або теговані (trunk) залежно від конфігурації.

Чому це добре: потужно, масштабовано, чиста топологія. Один міст — багато VLAN, менше інтерфейсів.

Сценарій відмови: потужність означає, що легко зробити помилку. Відсутній PVID або неправильне правило egress — й трафік зникає без драм і вибачень.

Мій операційний ухил: якщо ви невеликий або середній і хочете менше сюрпризів — Шаблон B найкращий баланс. Якщо ви будуєте платформу і можете дозволити дисципліну конфігурування й тестування — Шаблон C відмінний.

Жарт №2: VLAN-и не «випадають випадково». Вони ламаються детерміністично — просто часто без документації.

Приклади netplan, що працюють (і чому)

Ubuntu 24.04 зазвичай використовує netplan для генерації systemd-networkd конфігів на серверах. Найпоширеніша помилка — змішувати припущення NetworkManager з networkd-реальністю або лишати напівналаштовані інтерфейси.

Приклад 1: Простий нетегований міст br0

Switchport: access VLAN X (нетегований).
Хост: IP знаходиться на br0 через DHCP або статично.

cr0x@server:~$ sudo cat /etc/netplan/01-br0.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp3s0:
      dhcp4: no
      dhcp6: no
  bridges:
    br0:
      interfaces: [enp3s0]
      dhcp4: yes
      parameters:
        stp: false
        forward-delay: 0

Чому: enp3s0 не має IP; br0 має. Вимкнення STP уникне 30+ секунд «чому після перезавантаження нічого не проходить?» у простих топологіях.

Приклад 2: Мости для кожного VLAN (Шаблон B)

Switchport: trunk; VLANи 10 і 20 allowed/tagged.
Хост: management на VLAN 10; VM використовують VLAN 20.

cr0x@server:~$ sudo cat /etc/netplan/01-vlan-bridges.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp3s0:
      dhcp4: no
      dhcp6: no
  vlans:
    enp3s0.10:
      id: 10
      link: enp3s0
    enp3s0.20:
      id: 20
      link: enp3s0
  bridges:
    br10:
      interfaces: [enp3s0.10]
      dhcp4: yes
      parameters:
        stp: false
        forward-delay: 0
    br20:
      interfaces: [enp3s0.20]
      dhcp4: no
      dhcp6: no
      parameters:
        stp: false
        forward-delay: 0

Чому: br10 і br20 явні. Ваша VM на br20, і ви не можете випадково опинитися в мережі управління, якщо цього не захотіли.

Приклад 3: VLAN-aware міст (Шаблон C) з IP хоста лише на VLAN управління

Це просунутий хід. IP хоста знаходиться на VLAN-підінтерфейсі (management), а міст несе кілька VLAN для VM.

cr0x@server:~$ sudo cat /etc/netplan/01-vlan-aware-bridge.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp3s0:
      dhcp4: no
      dhcp6: no
  bridges:
    br0:
      interfaces: [enp3s0]
      dhcp4: no
      parameters:
        stp: false
        forward-delay: 0
  vlans:
    br0.10:
      id: 10
      link: br0
      dhcp4: yes

Чому: br0 — чисто L2; br0.10 — L3-присутність хоста для управління. VM підключаються до br0 і розподіляються по VLANам через bridge VLAN filtering (налаштовується поза netplan, зазвичай через networkd або явні bridge-команди під час завантаження).

Операційне попередження: netplan не виражає всього, що може знадобитися для bridge VLAN filtering per-port. Якщо йдете шляхом Шаблону C — ставтеся до хоста як до маленької комутаційної платформи: налаштовуйте послідовно і тестуйте після кожної зміни.

Безпечне застосування netplan

cr0x@server:~$ sudo netplan try
Do you want to keep these settings?

Press ENTER before the timeout to accept the new configuration
Changes will revert in 120 seconds

Значення: netplan try дає вікно для відкату. Використовуйте на віддалених системах, якщо ви не любите вихідні консолі.

Рішення: Якщо зв’язок падає — дочекайтеся відкату і спокійно виправте YAML.

Libvirt/KVM підключення: уникнення пастки «воно на virbr0»

За замовчуванням libvirt оптимізує мережі для «розробницький ноутбук запускає VM з інтернетом через NAT». У продакшні зазвичай хочуть бриджовану мережу, щоб VM була повноцінним елементом LAN/VLAN.

Перевірте, які мережі існують

cr0x@server:~$ virsh net-list --all
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

Значення: Існує стандартна libvirt NAT-мережа. Це не зло; просто часто не те, що потрібно.

Рішення: Вирішіть явно: NAT (default) чи bridge (br0/br10/br20). Не дозволяйте libvirt вирішувати випадково.

Прикріпити NIC VM до мосту (приклад)

cr0x@server:~$ virsh attach-interface --domain vm1 --type bridge --source br20 --model virtio --config
Interface attached successfully

Значення: Персистентна зміна конфігурації. Можливо, потрібно від’єднати старий NIC або перезавантажити VM залежно від підтримки hotplug.

Рішення: Після змін перевірте domiflist і потім перевірте зсередини VM.

Підтвердити, що NIC VM опинився там, де ви хотіли

cr0x@server:~$ virsh domiflist vm1
 Interface   Type     Source   Model    MAC
-------------------------------------------------------
 vnet3       bridge   br20     virtio   fe:54:00:aa:bb:cc

Значення: Тепер ви бриджовані до br20. Якщо інтернет все ще не працює — це не тому, що ви випадково залишилися на virbr0.

Рішення: Продовжуйте перевіряти VLAN і фаєрвол.

Типові помилки: симптом → корінь проблеми → виправлення

1) VM отримує IP, але не пінгує шлюз

Симптом: DHCP працює, але ping до першого хопу не проходить.
Корінь: DHCP приходить звідкись ще (relay, неправильний VLAN), або шлюз у іншому VLAN, ніж ефективний VLAN VM.
Виправлення: Захопіть ARP на vnet та аплінку. Підтвердіть VLAN-тегування і режим switchport. Вирівняйте access/native VLAN з нетегованим мостом або правильно тегуйте VLAN.

2) VM може пінгувати шлюз, але не публічні IP

Симптом: L2 в порядку; L3 за шлюзом не працює.
Корінь: Upstream маршрутизація/NAT/ACL, або неправильний маршрут за замовчуванням у гості.
Виправлення: Перевірте таблицю маршрутів гостя. Перевірте upstream ACL. Якщо хост робить маршрутизацію/NAT — увімкніть ip_forward і налаштуйте NAT правила свідомо.

3) VM може дістатися публічних IP, але DNS не працює

Симптом: ping 1.1.1.1 працює, пінг на хостнейм — ні.
Корінь: DNS-сервери недоступні, неправильний resolv.conf/systemd-resolved у гості або блокування UDP/TCP 53.
Виправлення: Запитайте DNS напряму; перевірте фаєрвол на UDP/TCP 53. Перевірте стан systemd-resolved у гості.

4) Працюють лише деякі VLAN; інші мертві

Симптом: VLAN 10 працює, VLAN 20 — ні на всіх VM.
Корінь: На switch trunk не дозволено VLAN 20, або таблиця VLAN мосту хоста не містить членства для VLAN 20.
Виправлення: Додайте VLAN до allowed list на switch та налаштування VLAN на хості. Перевірте bridge vlan show і tcpdump з фільтром vlan.

5) Інтернет працює до перезавантаження; потім VM ізольовані

Симптом: Ручні налаштування мосту/VLAN допомогли, але не збереглися.
Корінь: Ручні runtime-команди для мосту не закодовані в netplan/systemd-networkd; перезавантаження стирає стан.
Виправлення: Зробіть конфігурацію декларативною (netplan + networkd drop-ins) і зберігайте в контролі версій. Тестуйте з перезавантаженням як частиною зміни.

6) Хост може дістатися мережі; VM — ні

Симптом: Хост ping працює; VM — ні; міст виглядає в порядку.
Корінь: nftables forward policy скидає мостовий трафік, або bridge netfilter взаємодіє з правилами фаєрвола.
Виправлення: Перевірте ланцюг forward у nft і sysctls bridge-nf. Додайте явні accept правила для підмереж/мостів VM.

7) Трафік VM нестабільний; ARP флапає

Симптом: Іноді шлюз доступний; іноді ні; MAC адреси ніби рухаються.
Корінь: Дубльовані IP, MAC spoofing-фільтри на комутаторі або кілька мостів з аплінками, що створюють петлю (і STP не захищає).
Виправлення: Шукайте дублікати ARP-відповідей, аудитуйте функції безпеки комутатора і переконайтеся, що є тільки один L2-шлях до VLAN, якщо ви не робите redundancy навмисно.

8) Все працює, але продуктивність жахлива

Симптом: Висока затримка, мала пропускна здатність, падіння під навантаженням.
Корінь: MTU mismatch (особливо з VLAN-тегуванням), offload-особливості або хост витрачає CPU через фаєрвол/conntrack на мостовому трафіку.
Виправлення: Перевірте MTU по всьому шляху. Оцініть offload-настройки. Не ставте stateful фаєрвол у path форвардингу без розрахунку ресурсів.

Чеклісти / покроковий план

Покроково: Побудувати бриджовану мережу VM на одному VLAN (скучно і правильно)

  1. Виберіть Шаблон A (нетегований), якщо потрібен лише один VLAN.
  2. Налаштуйте netplan так, щоб фізична NIC не мала IP і була підпорядкована br0.
  3. Застосуйте netplan з netplan try.
  4. Перевірте: ip -br addr показує IP на br0.
  5. Прикріпіть NIC VM до br0 (тип bridge в libvirt).
  6. Перевірте: bridge link показує vnetX master br0.
  7. Тестуйте в VM: ping до шлюзу, потім до публічної IP, потім DNS.
  8. Якщо збій: tcpdump на vnetX та аплінку, щоб знайти перший відсутній кадр.

Покроково: Додати VLAN, не зробивши майбутнього себе нещасним

  1. Обирайте Шаблон B, якщо немає сильної причини для VLAN-aware мосту.
  2. Налаштуйте switchport як trunk з явним allowed VLAN списком.
  3. Створіть VLAN підінтерфейси на хості (enp3s0.10, enp3s0.20).
  4. Створіть per-VLAN мости (br10, br20). Помістіть IP управління хоста лише на одному VLAN.
  5. Прикріпіть VM до правильного мосту для їхнього VLAN. Не «використовуйте br0 для всього».
  6. Документуйте відображення VLAN → міст у репозиторії з netplan конфігами.
  7. Тестуйте з перезавантаженням. Завжди.

Чекліст валідації (після кожної зміни)

  • Хост: членство в мості коректне (bridge link).
  • Хост: IP на мосту (або на мостовому VLAN-інтерфейсі, навмисно).
  • Хост: членство VLAN відповідає очікуванням switchport.
  • Хост: фаєрвол дозволяє потрібні потоки у ланцюгу forward.
  • Гість: правильний маршрут + DNS.
  • Пакет: ARP виходить з VM, виходить із хоста і відповіді повертаються.

Три корпоративні міні-історії з мережевих окопів

Міні-історія №1: Інцидент через неправильне припущення

В одній компанії віртуалізаційний кластер стандартизували на trunk аплінку: VLAN 10 для управління, VLAN 20 для робочих навантажень. Інженер, який збудував перший хост, припустив, що switchport має native VLAN 20, бо «ми зазвичай так робимо». Він зробив Шаблон A: нетегований br0, VM підключені, немає тегування ніде.

Воно працювало в їхньому стояку. Не працювало в наступному. Та сама модель сервера, той самий netplan, той самий гіпервізор. Половина VM мала інтернет; інша половина не могла навіть ARPити шлюз. Нетворк-команда клялася, що нічого не змінювала. Потім хтось запитав єдине важливе питання: «Чи дійсно switchport в усіх стояках однакові?»

Виявилось — ні. В одному стояку native VLAN був 20. В іншому — 10. Третій мав іншу конфігурацію через інший шаблон місяцями раніше. Нетегований трафік потрапляв туди, куди комутатор вирішував, іншими словами — «ви не контролюєте це».

Виправлення не було в «більше перезапусків» чи «нових образах VM». Виправлення — перестати залежати від поведінки native VLAN. Вони перейшли на Шаблон B: явні теговані VLAN-підінтерфейси і per-VLAN мости. Це зайняло вікно обслуговування, але після цього стояки перестали бути сніжинками. Постмортем мав ключовий рядок: припущення — це конфігурація, просто недокументована.

Міні-історія №2: Оптимізація, що обернулась проти

Інша організація хотіла зменшити кількість інтерфейсів на хостах. Вони мали міст на кожен VLAN, і хтось вирішив, що це «занадто багато пристроїв». Тож вони перейшли на один VLAN-aware міст з фільтрацією, налаштований через набори runtime-скриптів на старті. Виглядало чисто: один міст, trunk аплінк, VM призначають VLANи динамічно.

А потім перший справжній інцидент: після оновлення ядра і перезавантаження частина хостів піднялась з відсутніми VLAN-записами на деяких vnet-портах. Ніхто не помітив одразу, бо самі хости були в порядку на VLAN управління. Але tenant VM на деяких VLAN були ізольовані. Симптоми типові: DHCP таймаути, ARP incomplete, немає доступу до шлюзу.

Корінь не в «Linux забуває VLANи». Він був у їхніх скриптах і порядку запуску. systemd-networkd піднімав міст, libvirt запускало VM рано, а скрипт членства VLAN виконувався пізніше — без надійного backfill правил для портів. Деякі порти мали PVID, деякі — ні. Умовна гонка стала мережею політики.

Вони відкотилися до Шаблону B для більшості кластерів і залишили Шаблон C тільки там, де мали час закодити правила VLAN детерміністично, версіонувати і гарантувати порядок старту. Оптимізація не злетіла, бо метод деплойменту не був таким нудним, як мав бути.

Міні-історія №3: Нудна, але правильна практика, що врятувала день

Фінансова команда експлуатувала KVM на Ubuntu з бриджованою мережею і VLAN. Нічого надзвичайного. Але була одна звичка: після кожної зміни мережі вони запускали стандартний скрипт валідації, який збирав три речі — членство мосту, таблицю VLAN і політику nftables forward — і зберігав вивід у записі зміни.

Одного ранку кілька VM втратили вихідну доступність. Хост виглядав «up». Міст «up». Switchport «up». Тут команди зазвичай починають перезавантажувати все, поки щось не зміниться. Вони не стали цього робити. Порівняли останні відомі добрі виводи з поточними.

Різниця була маленька і вирішальна: політика forward змінилася на drop, і accept-правило для br0 → аплінк зникло. Виявилось, що оновили роль hardening, яка була коректною для standalone серверів, але некоректною для хостів віртуалізації, що форвардять трафік.

Виправлення зайняло хвилини: додали відсутнє accept-правило (правильно скоуплене), перевпровадили роль з урахуванням типу хоста і відновили сервіс. Нудна практика не була геніальною. Вона була доказом. Доказ перемагає паніку щоразу.

FAQ

1) Чи використовувати NetworkManager чи systemd-networkd на серверах Ubuntu 24.04?

Використовуйте systemd-networkd (через netplan) для серверів, якщо немає конкретної причини стандартизуватися на NetworkManager. Змішування їх — шлях до «примарних конфігів».

2) Моя VM прикріплена до br0, а все одно використовує адреси 10.0.2.0/24. Чому?

Зазвичай це libvirt NAT (default network). Перевірте virsh domiflist. Якщо source — default і type — network, ви не на bridge.

3) Чи потрібен STP на Linux-місті?

Зазвичай ні для одного аплінку, одного мосту і відсутності петель. STP може додавати затримки форвардингу і плутанину. Вмикайте лише коли впевнені, що є потенційні L2-петлі і ви хочете захист.

4) Який найчистіший спосіб помістити VM у різні VLANи?

Per-VLAN мости (Шаблон B) — найчистіший в операційному сенсі. VLAN-aware bridge filtering (Шаблон C) потужний, але вимагає дисципліни конфігурації.

5) Чи може гість сам робити VLAN-тегування?

Так. Можна презентувати trunk VM і нехай вона створює VLAN-підінтерфейси всередині. Це підходить для маршрутизаторів/фаєрволів або вузлів Kubernetes, які керують VLANами. Для звичайних VM тримайте VLAN-логіку на хості або upstream.

6) Чому DHCP працює, а ARP до шлюзу — ні?

Тому що DHCP може приходити через relay або через некоректно тегований прийом, що не гарантує L2-суміжності зі шлюзом. Доведіть правильність VLAN за допомогою tcpdump і стану ARP, а не «вона отримала IP».

7) Чи безпечно фільтрувати трафік VM на хості за допомогою nftables?

Так, якщо ви робите це навмисно і розумієте, чи проходять мостові кадри через iptables/nftables через налаштування bridge-nf. Небезпечно — «policy drop» без потрібних accept-правил.

8) Як дізнатися, проблема в switchport чи в хості?

Захопіть трафік з обох боків мосту хоста: vnet інтерфейс і фізичний аплінк. Якщо пакети виходять з vnet, але не з аплінку — це на боці хоста. Якщо вони виходять з аплінку, але відповіді не повертаються — upstream (switch/VLAN/ACL).

9) Чи повинен хост мати IP на кожному VLAN, який використовують VM?

Ні. У чистому L2-бриджованому дизайні хосту не потрібно L3-присутності на VLANах VM. Додавайте IP хосту лише коли є чітка операційна потреба (моніторинг, маршрутизація, сервіси) і ви можете це захистити.

10) Що з MTU і VLAN-накладенням?

802.1Q додає накладення; невідповідність MTU може спричиняти дивні часткові збої (особливо коли PMTUD блокується). Якщо використовуєте jumbo frames — перевірте MTU по всьому шляху: NIC хоста, міст, NIC VM і switchport.

Висновок: наступні кроки, які не зашкодять у майбутньому

Якщо у вашої Ubuntu 24.04 VM «немає інтернету», утримайтеся від спокуси переконфігурувати все одразу. Ваше завдання — знайти перший зламаний хоп, а потім виправити дизайн так, щоб він залишався виправленим.

  1. Оберіть шаблон: A (нетегований), B (per-VLAN мости) або C (VLAN-aware міст). Не змішуйте їх легковажно.
  2. Зробіть конфігурацію хоста декларативною: netplan + networkd, застосовано через netplan try.
  3. Доведіть членство мосту: vnet інтерфейс на правильному мосту; фізичний аплінк прикріплений.
  4. Доведіть VLAN-реальність: таблиця VLAN мосту збігається з режимом switchport і allowed VLANs.
  5. Доведіть, що форвардинг не блокується: nftables forward chain і bridge-nf налаштування відповідають намірам.
  6. Операціоналізуйте валідацію: тримайте набір команд, які ви виконуєте після кожної зміни, і зберігайте їхній вивід.

Коли ви робите так, «VM немає інтернету» перестає бути таємницею і стає тим, чим має бути: прямим завданням з ізоляції несправності з постійним виправленням наприкінці.

← Попередня
ZFS zpool checkpoint: аварійна кнопка “відмінити” (із гострими краями)
Наступна →
Ubuntu 24.04 «Failed to start …»: найшвидший робочий процес діагностики systemd (випадок №2)

Залишити коментар