Як працює VLAN у Linux

27.06.2025 4 хвилин Автор: Lady Liberty

Віртуальні мережі VLAN у Linux — це ефективний спосіб розділення мережевого трафіку без використання фізичних комутаторів. У цій статті ми розглянемо, як за допомогою інструментів Linux — таких як network namespaces, veth-пари, bridge-з’єднання та утиліта ethsend — створити повноцінну VLAN-інфраструктуру.

Розпочнемо

У цій лабораторній роботі ми побачимо, як використовувати вбудовані можливості VLAN моста Linux для розділення одного широкомовного домену на кілька менших доменів, які потім можна використовувати для налаштування належним чином ізольованих IP-підмереж.

Передумови

Ми використовуватимемо інструменти віртуалізації мережі Linux для:

На ігровому майданчику зручно надано набір допоміжних скриптів для спрощення процесу створення кінцевих хостів та комутаторів. Якщо ви використовуєте власну машину з Linux для проходження курсу, просто скопіюйте скрипти з цієї сторінки.

create_bridge– створює новий мережевий простір імен з мостовим пристроєм Linux; міст налаштовано на фільтрацію трафіку за ідентифікатором VLAN за допомогою vlan_filtering 1опції:

create_bridge() {
  local nsname="$1"
  local ifname="$2"

  echo "Creating bridge ${nsname}/${ifname}"

  ip netns add ${nsname}
  ip netns exec ${nsname} ip link set lo up
  ip netns exec ${nsname} ip link add ${ifname} type bridge
  ip netns exec ${nsname} ip link set ${ifname} up

  # Enable VLAN filtering on bridge.
  ip netns exec ${nsname} ip link set ${ifname} type bridge vlan_filtering 1
}

create_end_host– створює новий мережевий простір імен з пристроєм veth у ньому, який знаходиться у вказаній VLAN (інший кінець пари veth підключено до мосту):

create_end_host() {
  local host_nsname="$1"
  local peer1_ifname="$2"
  local peer2_ifname="$2b"
  local vlan_vid="$3"
  local bridge_nsname="$4"
  local bridge_ifname="$5"

  echo "Creating end host ${host_nsname} connected to ${bridge_nsname}/${bridge_ifname} bridge (VLAN ${vlan_vid})"

  # Create end host network namespace.
  ip netns add ${host_nsname}
  ip netns exec ${host_nsname} ip link set lo up

  # Create a veth pair connecting end host and bridge namespaces.
  ip link add ${peer1_ifname} netns ${host_nsname} type veth peer \
              ${peer2_ifname} netns ${bridge_nsname}
  ip netns exec ${host_nsname} ip link set ${peer1_ifname} up
  ip netns exec ${bridge_nsname} ip link set ${peer2_ifname} up

  # Attach peer2 interface to the bridge.
  ip netns exec ${bridge_nsname} ip link set ${peer2_ifname} master ${bridge_ifname}

  # Put host into right VLAN
  ip netns exec ${bridge_nsname} bridge vlan del dev ${peer2_ifname} vid 1
  ip netns exec ${bridge_nsname} bridge vlan add dev ${peer2_ifname} vid ${vlan_vid} pvid ${vlan_vid}
}

Дитячий майданчик також надає інструмент ethsendдля ручної передачі довільних даних на канальному рівні. Інструмент використовує пакетні сокети ( AF_PACKET), що працюють у необробленому режимі ( SOCK_RAW), для програмної надсилання кадрів Ethernet. На щастя, кадри Ethernet мають досить просту структуру, тому їх досить легко створити в коді, а потім записати в необроблений пакетний сокет.

#!/usr/bin/env python3

# Usage: ethsend eth0 ff:ff:ff:ff:ff:ff 'Hello everybody!'
#        ethsend eth0 06:e5:f0:20:af:7a 'Hello 06:e5:f0:20:af:7a!'
#
# Note: CAP_NET_RAW capability is required to use SOCK_RAW

import fcntl
import socket
import struct
import sys

def send_frame(ifname, dstmac, eth_type, payload):
  # Open raw socket and bind it to network interface.
  s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
  s.bind((ifname, 0))

  # Get source interface's MAC address.
  info = fcntl.ioctl(s.fileno(),
                     0x8927,
                     struct.pack('256s', bytes(ifname, 'utf-8')[:15]))
  srcmac = ':'.join('%02x' % b for b in info[18:24])

  # Build Ethernet frame
  payload_bytes = payload.encode('utf-8')
  assert len(payload_bytes) <= 1500  # Ethernet MTU

  frame = human_mac_to_bytes(dstmac) + \
          human_mac_to_bytes(srcmac) + \
          eth_type + \
          payload_bytes

  # Send Ethernet frame
  return s.send(frame)

def human_mac_to_bytes(addr):
  return bytes.fromhex(addr.replace(':', ''))

def main():
  ifname = sys.argv[1]
  dstmac = sys.argv[2]
  payload = sys.argv[3]
  ethtype = b'\x7A\x05'  # arbitrary, non-reserved
  send_frame(ifname, dstmac, ethtype, payload)

if __name__ == "__main__":
  main()

⚠️ CAP_NET_RAWдля запуску вищезазначеного коду потрібна функціональність (або просто використання sudo).

Як реалізована VLAN

Щоб розділити один сегмент мережі L2 на кілька непересічних підсегментів без будь-якої перемонтажі, використовується техніка, яка називається тегуванням кадрів . Формат кадру Ethernet змінюється, і додається додаткове поле довжиною 4 байти. Серед іншого, воно містить ідентифікатор VLAN . Кадри з різними ідентифікаторами VLAN логічно належать до різних доменів широкомовлення L2.

Існує більше одного способу позначення фреймів тегами. У цій лабораторній роботі позначення є прозорим для кінцевих вузлів і повністю реалізовано мостом.

Проста VLAN з використанням мосту Linux

У цьому прикладі показано, як налаштувати кілька доменів широкомовлення L2 за допомогою одного мосту Linux з кількома VLAN. Виконайте наведені нижче кроки, щоб відтворити його.

Спочатку створіть новий мережевий простір імен ( bridge1) з мостовим пристроєм ( br1) у ньому:

create_bridge bridge1 br1

Потім створіть кілька кінцевих хостів, підключених до мосту, та призначте їм однаковий ідентифікатор VLAN 10:

create_end_host host10 eth10 10 bridge1 br1
create_end_host host11 eth11 10 bridge1 br1
create_end_host host12 eth12 10 bridge1 br1

 

Після цього створіть ще один набір кінцевих хостів, підключених до того ж мосту, але призначивши їм інший ідентифікатор VLAN 20:

create_end_host host20 eth20 20 bridge1 br1
create_end_host host21 eth21 20 bridge1 br1
create_end_host host22 eth22 20 bridge1 br1

Щоб продемонструвати, що вищезгадані хости утворюють два ізольованих домени широкомовлення, почніть моніторинг їхнього трафіку.

Перша VLAN (використовуючи пару нових вкладок терміналу ):

# from host11
nsenter --net=/var/run/netns/host11 \
  tcpdump -i eth11 ether proto 0x7a05
# from host12
nsenter --net=/var/run/netns/host12 \
  tcpdump -i eth12 ether proto 0x7a05

Друга VLAN (використовуючи ще одну пару термінальних вкладок ):

# from host21
nsenter --net=/var/run/netns/host21 \
  tcpdump -i eth21 ether proto 0x7a05
# from host22
nsenter --net=/var/run/netns/host22 \
  tcpdump -i eth22 ether proto 0x7a05

Тепер надішліть два широкомовні кадри з перших хостів кожної VLAN (використовуючи ще одну вкладку терміналу ):

# from host10
nsenter --net=/var/run/netns/host10 \
  ethsend eth10 ff:ff:ff:ff:ff:ff 'Hello VLAN 10!'

# from host20
nsenter --net=/var/run/netns/host20 \
  ethsend eth20 ff:ff:ff:ff:ff:ff 'Hello VLAN 20!'

Уважно перевірте tcpdumpвихідні дані, щоб переконатися, що широкомовні кадри отримуються лише відповідними кінцевими хостами.

Зверніть увагу, що ні інтерфейси кінцевих хостів, ні скрипт надсилання Ethernet не повинні знати нічого про тегування VLAN. Налаштування VLAN у цій демонстрації повністю прозоре для кінцевих учасників. Міст призначає відповідні теги VLAN на основі вхідного порту кадру. Але це не єдиний можливий спосіб створення VLAN. Наприклад, тегування VLAN можна було б виконати на кінцевих хостах.

Ключовий висновок з цієї лабораторної роботи: VLAN – це конструкція L2, яку можна налаштувати на довільну кількість з’єднаних сегментів L2, розділяючи великий широкомовний домен на менші та забезпечуючи достатню ізоляцію для підмереж L3.

Щоб навести лад, просто видаліть створені простори імен мережі:

ip netns delete bridge1

ip netns delete host10
ip netns delete host11
ip netns delete host12

ip netns delete host20
ip netns delete host21
ip netns delete host22

Висновок

Ця лабораторна робота показує, наскільки потужними є вбудовані засоби Linux для мережевої віртуалізації. Без жодного фізичного обладнання ми створили повноцінну модель мережі з ізольованими VLAN, які діють на рівні L2, забезпечуючи поділ широкомовного трафіку. Механізм VLAN-фільтрації мосту Linux дозволяє створювати сегментовані мережі з високим рівнем гнучкості, а використання veth‑пар, network namespace і raw‑сокетів (ethsend) забезпечує точне моделювання реального трафіку.

Ключовий урок — належна ізоляція не вимагає складних рішень, достатньо знати, як грамотно застосовувати існуючі інструменти ядра Linux. Цей підхід стане у пригоді не лише для навчання, а й для розгортання тестових середовищ, перевірки конфігурацій або розробки мережевих сервісів у контролюваному середовищі.

Підписатися
Сповістити про
0 Коментарі
Найстаріші
Найновіше Найбільше голосів
Знайшли помилку?
Якщо ви знайшли помилку, зробіть скріншот і надішліть його боту.