Віртуальні мережі VLAN у Linux — це ефективний спосіб розділення мережевого трафіку без використання фізичних комутаторів. У цій статті ми розглянемо, як за допомогою інструментів Linux — таких як network namespaces, veth-пари, bridge-з’єднання та утиліта ethsend — створити повноцінну VLAN-інфраструктуру.
У цій лабораторній роботі ми побачимо, як використовувати вбудовані можливості VLAN моста Linux для розділення одного широкомовного домену на кілька менших доменів, які потім можна використовувати для налаштування належним чином ізольованих IP-підмереж.
Ми використовуватимемо інструменти віртуалізації мережі Linux для:
Емулювати окремі мережеві вузли (через мережеві простори імен )
Емуляція мережевих інтерфейсів (через пристрої veth )
Емулювати мережеві комутатори (через мостові пристрої ).
На ігровому майданчику зручно надано набір допоміжних скриптів для спрощення процесу створення кінцевих хостів та комутаторів. Якщо ви використовуєте власну машину з 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).
Щоб розділити один сегмент мережі L2 на кілька непересічних підсегментів без будь-якої перемонтажі, використовується техніка, яка називається тегуванням кадрів . Формат кадру Ethernet змінюється, і додається додаткове поле довжиною 4 байти. Серед іншого, воно містить ідентифікатор VLAN . Кадри з різними ідентифікаторами VLAN логічно належать до різних доменів широкомовлення L2.
Існує більше одного способу позначення фреймів тегами. У цій лабораторній роботі позначення є прозорим для кінцевих вузлів і повністю реалізовано мостом.
У цьому прикладі показано, як налаштувати кілька доменів широкомовлення 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. Цей підхід стане у пригоді не лише для навчання, а й для розгортання тестових середовищ, перевірки конфігурацій або розробки мережевих сервісів у контролюваному середовищі.