View on GitHub

Methodics of Linux Network Protocols

Practical materials for learning TCP/IP and its implementation on Linux

Среды передачи данных из нескольких носителей

Мы всё ближе подходим к задаче объединения всех абонентов в единый интернет. Однако для начала рассмотрим более простую задачу.

Пусть имеется несколько сред передачи данных с одним и тем же видом носителя. Физически это отдельные взаимодействующие множества абонентов. Задача будет следующая: обеспечить на интерфейсном уровне единую среду, работающую поверх носителя, в которой физически разные сети воспринимаются устройcтвами в виде единой локальной сети.

Логичное продолжение — объединение множества сред на разных носителях. Но… на поверку это оказывается задачей совершенно другого уровня: если интерфейсные протоколы значимо отличаются, нет смысла изобретать преобразователь любого формата фреймов в любой, который вдобавок пытается сохранить уникальность идентификаторов. Гораздо логичнее поднять решение вопрос на уровень выше — туда, где решается задача уникальной идентификации всех абонентов неоднородной сети. Об этом бы поговорим в следующей главе.

Коммутация фреймов

Цель данной главы — показать, каким образом задача объединения нескольких сред может быть решена непосредственно на интерфейсном уровне, и какие важные ограничения могут при этом возникнуть. Перенаправление пакета между абонентами сети называется маршрутизацией как в общем случае, независимо от уровня протокола, так и конкретно на сетевом уровне, который мы пока не рассматриваем. Поэтому перенаправление пакетов интерфейснного уровня — фреймов — мы назовём коммутацией, а устройства, которые решают такую задачу — коммутаторами.

Для настройки коммутации пакетов необходимо использовать специальные устройства — хаб и мост. Это могут быть как специализированные устройства, предназначенные исключительно для коммутации, так и многофункциональные абоненты сети, вплоть до компьютеров общего назначения под управлением Linux. Более правильно будет сказать, что коммутатор — это роль, которую данный абонент сети играет.

Хаб и сетевой мост

Хаб, он же сетевой концентратор — это устройство, которое, получив пакет на один интерфейс, ретранслирует его во все остальные.

Для настройки хаба на Linux-машине необходимо всего лишь подключить постоянный неразборчивый режим и пересылать все приходящие данные на все порты кроме, быть может, порта-источника. Такой режим работы хаба идентичен работе общей шины между устройствами. И, как и общая шина, хаб приносит достаточное количество трудностей передачи: именно для него верно правило «50% загруженности по времени — неработающая сеть».

Более универсальным решением является сетевой мост. Он также поддерживает неразборчивый режим работы, однако не строит работу только на нем.

Сетевой мост поддерживает таблицу абонентов. Это динамически обновляемая таблица соответствия между MAC-адресами и сетевыми интерфейсами, за которыми находятся абоненты с этими MAC-адресами. В случае не Ethernet таблица может описывать соответствия других идентификаторов и интерфейсов, но схема работы останется идентичной.

Если мост получает широковещательный фрейм, или фрейм, предназначенный неизвестному получателю, он вынужден работать как хаб — ретранслировать фрейм во все интерфейсы. Однако каждая такая ретрансляция запоминает, за каким интерфейсом находился отправитель и заполняет (или обновляет) строчку в таблице абонентов. Пока абонент не удалился из таблицы, ретрансляция пакета ему как получателю будет идти только по одному интерфейсу.

При включении моста, когда таблица абонентов ещё не заполнена данными, первые фреймы будут рассылаться широковещательно. Потенциально эту особенность работы можно использовать при сетевой атаке.

Контроль работы коммутаторов

При работе множества коммутаторов в одной локальной сети могут возникать различные проблемы передачи.

Самая простая из них — зацикливание пакетов между мостами. Для её решения разработан специальный протокол STP - Spanning Tree Protocol. Технически он отсекает доступ к некоторым интерфейсам у мостов, оставляя только полносвязное дерево абонентов.

Для предотвращения сетевых атак на таблицы абонентов разработаны различные antispoof-алгоритмы, позволяющие вычислять и блокировать источники атаки, закрывая им доступ к сети. Например, такую защиту обеспечивает firewall L2 в высокоуровневой утилите nftables. На интерфейсном уровне устанавливается специальный фильтр фреймов, основанный на MAC-адресации. К сожалению, из-за возможности смены MAC-адресов у большинства устройств данный способ не обеспечивает полной защиты от атак.

Создание моста

На виртуальных машинах настроим взаимодействие двух абонентов через мост. Для этого создадим три устройства со следующими соединениями:

srv:
        eth1: net1
client:
        eth1: net2
bridge:
        eth1: net1
        eth2: net2

Запустим наши машины. После запуска «поднимем» сетевые интерфейсы на машинах srv и client.

srv

[root@srv ~]# ip link set eth1 up  
[root@srv ~]#

client

[root@client ~]# ip link set eth1 up  
[root@client ~]#  

Проверим связность сети между нашими абонентами. Для этого необходимо организовать между ними передачу трафика. В прошлой главе мы говорили о возможностях socat для передачи данных не выше интерфейсного уровня. Однако данный способ далеко не самый удобный. В будущем вне зависимости от уровня, на котором мы работаем, мы будем использовать более высокоуровневые способы определения связности.

Наши виртуальные машины поддерживают работу протокола IPv6. Благодаря этому при активации сетевых интерфейсов устройство автоматически запускает цикл настройки IPv6-адреса на базе MAC-адреса. Сам механизм настройки мы обсудим в будущих главах, сейчас достаточно знать, что после включения сетевого интерфейса на нём автоматически генерируется IPv6-адрес, по которому можно проверять связность устройства.

srv

[root@srv ~]# ip addr show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000  
   link/ether 08:00:27:05:4a:9e brd ff:ff:ff:ff:ff:ff
   altname enp0s8
   altname enx080027054a9e
   inet6 fe80::a00:27ff:fe05:4a9e/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever

[root@srv ~]# ip addr show eth1 | grep inet6  
   inet6 fe80::a00:27ff:fe05:4a9e/64 scope link proto kernel_ll
[root@srv ~]#

client

[root@client ~]# ip addr show eth1 | grep inet6  
   inet6 fe80::a00:27ff:fea0:ff92/64 scope link proto kernel_ll
[root@client ~]#

Для проверки связности будем использовать утилиту traceroute. Чтобы не отправлять избыточное количество пакетов (что для проверки связности абонентов не требуется), установим специальные флаги:

Ещё одна особенность при работе с IPv6 — другой формат отслеживания адресов для маршрутизации. Сейчас это означает необходимость явного указания, через какой интерфейс необходимо вести передачу.

srv

[root@srv ~]# traceroute -q1 -m1 fe80::a00:27ff:fea0:ff92%eth1
traceroute to fe80::a00:27ff:fea0:ff92%eth1 (fe80::a00:27ff:fea0:ff92%eth1), 1 hops max, 80 byte packe
ts  
1  srv (fe80::a00:27ff:fe05:4a9e%eth1)  3104.244 ms !H
[root@srv ~]#

Логично было ожидать, что связности нет: метка !H ставится, когда абонент не может понять, кому предназначен пакет — в нашем случае это означает, что устройства находятся в разных сетях. Теперь с помощью моста объединим их в единую сеть. Для специальных команд, связанных с работой моста, необходимо использовать ключевое слово bridge.

Для начала необходимо создать логический интерфейс типа bridge. После создания он отобразится со всеми интерфейсами:

bridge

[root@bridge ~]# ip link add dev br0 type bridge  
[root@bridge ~]# ip link show br0
6: br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000  
   link/ether da:12:01:0e:cb:3c brd ff:ff:ff:ff:ff:ff
   inet6 fe80::a00:27ff:fe0e:cb3c/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
[root@bridge ~]# 

Теперь включим все интерфейсы (два сетевых и созданный мост), и установим для eth1 и eth2 мастер-интерфейс моста:

bridge

[root@bridge ~]# ip link set eth1 up  
[root@bridge ~]# ip link set eth2 up  
[root@bridge ~]# ip link set br0 up  
[root@bridge ~]# ip link set eth1 master br0  
[root@bridge ~]# ip link set eth2 master br0  

Заметим, что никаких настроек относительно маршрутизации пакетов на bridge не описано. «Под капотом» виртуального интерфейса типа bridge работает протокол STP, который призван обеспечить связность абонентов, так что правила пересылки фреймов из интерфейса в интерфейс сообразно STP появляются по умолчанию:

bridge

[root@bridge ~]# bridge link  
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 5
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 5

Теперь попробуем передать данные между сервером и клиентом. За время настройки мост уже заполнил часть динамической таблицы известными ему данными, но в них пока нет информации об абонентах.

bridge

[root@bridge ~]# bridge fdb  
08:00:27:6f:93:4f dev eth1 vlan 1 master br0 permanent  
08:00:27:6f:93:4f dev eth1 master br0 permanent  
01:00:5e:00:00:01 dev eth1 self permanent  
08:00:27:85:f5:da dev eth2 vlan 1 master br0 permanent  
08:00:27:85:f5:da dev eth2 master br0 permanent  
01:00:5e:00:00:01 dev eth2 self permanent  
01:00:5e:00:00:6a dev br0 self permanent  
01:00:5e:00:00:01 dev br0 self permanent  

Перед отправкой данных с сервера включим отслеживание таблицы моста (команда bridge monitor):

bridge

[root@bridge ~]# bridge monitor  

Проверим связность сети через traceroute:

srv

[root@srv ~]# traceroute -q1 -m1 fe80::a00:27ff:fea0:ff92%eth1
traceroute to fe80::a00:27ff:fea0:ff92%eth1 (fe80::a00:27ff:fea0:ff92%eth1), 1 hops max, 80 byte packe
ts  
1  fe80::a00:27ff:fea0:ff92%eth1 (fe80::a00:27ff:fea0:ff92%eth1)  3.627 ms
[root@srv ~]#

Связность между абонентами появилась (нет метки в логах данных, есть время передачи фрейма). При этом мост внёс в таблицу новые MAC-адреса и соответствующие им сетевые интерфейсы. По истечении тайм-аута в отсутствие передачи данных мост удаляет записи из таблицы по причине их (возможной) неактуальности.

bridge

[root@bridge ~]# bridge monitor  
08:00:27:05:4a:9e dev eth1 master br0
08:00:27:a0:ff:92 dev eth2 master br0
<...* minutes later...>
Deleted 08:00:27:a0:ff:92 dev eth2 master br0 stale  
Deleted 08:00:27:05:4a:9e dev eth1 master br0 stale

Убедиться в том, что пакеты, действительно проходят через мост, можно путём мониторинга интерфейса br0:

bridge

[root@bridge ~]# tcpdump -XXei br0 udp  
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode  
listening on br0, link-type EN10MB (Ethernet), snapshot length 262144 bytes  

srv

[root@srv ~]# traceroute -q1 -m1 fe80::a00:27ff:fea0:ff92%eth1
traceroute to fe80::a00:27ff:fea0:ff92%eth1 (fe80::a00:27ff:fea0:ff92%eth1), 1 hops max, 80 byte packe
ts  
1  fe80::a00:27ff:fea0:ff92%eth1 (fe80::a00:27ff:fea0:ff92%eth1)  1.382 ms
[root@srv ~]#

bridge

[root@bridge ~]# tcpdump -XXei br0 udp  
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode  
listening on br0, link-type EN10MB (Ethernet), snapshot length 262144 bytes  
14:30:10.104426 08:00:27:05:4a:9e (oui Unknown) > 08:00:27:a0:ff:92 (oui Unknown), ethertype IPv6 (0x86  
dd), length 94: fe80::a00:27ff:fe05:4a9e.55682 > fe80::a00:27ff:fea0:ff92.traceroute: UDP, length 32  
       0x0000:  0800 27a0 ff92 0800 2705 4a9e 86dd 6001  ..'.....'.J...`.
       0x0010:  3deb 0028 1101 fe80 0000 0000 0000 0a00  =..(............
       0x0020:  27ff fe05 4a9e fe80 0000 0000 0000 0a00  '...J...........
       0x0030:  27ff fea0 ff92 d982 829a 0028 06a4 4041  '..........(..@A
       0x0040:  4243 4445 4647 4849 4a4b 4c4d 4e4f 5051  BCDEFGHIJKLMNOPQ
       0x0050:  5253 5455 5657 5859 5a5b 5c5d 5e5f       RSTUVWXYZ[\]^_
^C
1 packets captured
1 packets received by filter
0 packets dropped by kernel  
[root@bridge ~]#

В более сложных топологиях можно проверить и другие свойства STP:

VLAN - Virtual Local Area Network

При обсуждении VLAN стоит различать два определения этого термина. «Инженерный» термин VLAN означает группу интерфейсов, объединённых в единую среду передачи данных, которая изолирована от других групп интерфейсов. Реализовать такое поведение коммутаторов можно по-разному. Например, создание таких групп может быть просто выведено в интерфейс управления коммутатором.

Другой вариант реализации — снабдить каждый фрейм дополнительным полем, в котором явно указывать такую изолированную группу, и принимать решение о коммутации на основании этого поля. Такую задачу решает семейство протоколов IEEE_802.1Q. Использование в сети таких модифицированных 802.1Q-фреймов — это другое определение термина VLAN, «теоретическое».

На текущий момент технологию IEEE_802.1Q поддерживают все сетевые карты. Более того, модификации протокола способны обработать фреймы с двумя тегами подряд и другими надстройками VLAN.

Большая часть текстов про VLAN — это методички по настройке разнообразных топологий на разнообразном «железе», так что в них используется «инженерное» понимание термина. Как следствие, возникают понятия «тегированного» VLAN-а (т. е. канала с поддержкой протокола 802.1Q и определённым VID в теге фрейма) и «нетегированного» VLAN-а (канала с «простыми» фреймами без тега 802.1Q, объединение и разделение которых диктуется исключительно программным обеспечением на коммутаторе). Мы будем придерживаться «теоретической» терминологии: фраза «фрейм из VLAN-а такого-то» означает 802.1Q-фрейм с определённым VID, а просто «фрейм» — просто фрейм.

На практике использование IEEE_802.1Q-протокола удобно при создании независимых сетей из нескольких сред передач данных каждая, работающих на одном физическом оборудовании. Пример организации двух VLAN на одном физическом мосту продемонстрирован на картинке:

Добавление VLAN

Вернёмся к топологии с сетевым мостом и добавим в неё поддержку 802.1Q-фреймов через другой мост на bridge.

Для начала на каждом из абонентов необходимо настроить виртуальные интерфейсы, через которые будут проходить фреймы с соответствующим тегом. При отправке данных фреймы, проходящие через VLAN-интерфейс, будут получать заголовок и выходить в канал уже с тегом. При получении данных все фреймы с соответствующим VLAN-тегом будут направляться в эти интерфейсы, где с них будет сниматься тег.

srv

[root@srv ~]# ip link add link eth1 name vlan5 type vlan id 5  
[root@srv ~]# ip link set vlan5 up  
[root@srv ~]#

client

[root@client ~]# ip link add link eth1 name vlan5 type vlan id 5  
[root@client ~]# ip link set vlan5 up  
[root@client ~]#

На bridge также сделаем VLAN-интерфейсы, чтобы отдельно проводить трафик VLAN по устройству. Между этими интерфейсами внутри bridge фреймы передаются без тега — он снимается при выходе с одного интерфейса и вновь надевается при входе в другой. Общий трафик в устройстве не будет отличим от трафика с тегами. Для их разделения и делается отдельный мост, хотя формально новые интерфейсы можно было привязать и к старому.

bridge

[root@bridge ~]# ip link add link eth1 name vlan51 type vlan id 5  
[root@bridge ~]# ip link add link eth2 name vlan52 type vlan id 5  
[root@bridge ~]#   
[root@bridge ~]# ip link add dev brvlan type bridge  
[root@bridge ~]# ip link set vlan51 master brvlan  
[root@bridge ~]# ip link set vlan52 master brvlan  
[root@bridge ~]#
[root@bridge ~]# ip link set vlan51 up  
[root@bridge ~]# ip link set vlan52 up  
[root@bridge ~]# ip link set brvlan up  
[root@bridge ~]#

Теперь запустим на bridge мониторинг трафика на eth1. Через него точно пройдут все фреймы, поскольку он является основным для vlan51, который будет вытягивать 802.1Q-фреймы из него. Отслеживание трафика здесь позволит увидеть оба вида трафика.

bridge

[root@bridge ~]# tcpdump -XXei eth1 udp  
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode  
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes

Запустим трафик между srv и client. Для начала сделаем это по уже привычному маршруту — через eth1. Поскольку трафик изначально не тегируется, он пройдёт по верхнему пути на картинке.

srv

[root@srv ~]# traceroute -q1 -m1 fe80::a00:27ff:fea0:ff92%eth1
traceroute to fe80::a00:27ff:fea0:ff92%eth1 (fe80::a00:27ff:fea0:ff92%eth1), 1 hops max, 80 byte packe
ts  
1  fe80::a00:27ff:fea0:ff92%eth1 (fe80::a00:27ff:fea0:ff92%eth1)  2.322 ms
[root@srv ~]#

bridge обнаружит этот трафик, в описании данных явно указано, что они не имеют тега.

bridge

[root@bridge ~]# tcpdump -XXei eth1 udp  
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode  
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes  
14:38:14.923344 08:00:27:05:4a:9e (oui Unknown) > 08:00:27:a0:ff:92 (oui Unknown), ethertype IPv6 (0x86  
dd), length 94: fe80::a00:27ff:fe05:4a9e.57532 > fe80::a00:27ff:fea0:ff92.traceroute: UDP, length 32  
       0x0000:  0800 27a0 ff92 0800 2705 4a9e 86dd 600d  ..'.....'.J...`.
       0x0010:  7255 0028 1101 fe80 0000 0000 0000 0a00  rU.(............
       0x0020:  27ff fe05 4a9e fe80 0000 0000 0000 0a00  '...J...........
       0x0030:  27ff fea0 ff92 e0bc 829a 0028 ff69 4041  '..........(.i@A
       0x0040:  4243 4445 4647 4849 4a4b 4c4d 4e4f 5051  BCDEFGHIJKLMNOPQ
       0x0050:  5253 5455 5657 5859 5a5b 5c5d 5e5f       RSTUVWXYZ[\]^_

Теперь запустим трафик через VLAN-интерфейс. Он пройдёт по нижнему пути на картинке.

srv

[root@srv ~]# traceroute -q1 -m1 fe80::a00:27ff:fea0:ff92%vlan5
traceroute to fe80::a00:27ff:fea0:ff92%vlan5 (fe80::a00:27ff:fea0:ff92%vlan5), 1 hops max, 80 byte pac
kets  
1  fe80::a00:27ff:fea0:ff92%vlan5 (fe80::a00:27ff:fea0:ff92%vlan5)  5.853 ms
[root@srv ~]#

Заметим, что время передачи кратно выросло. Это связано с дополнительными затратами на снятие и надевание тега. В мониторе bridge явно будет описано наличие метки в передаваемых данных.

bridge

<…>

14:38:40.187157 08:00:27:05:4a:9e (oui Unknown) > 08:00:27:a0:ff:92 (oui Unknown), ethertype 802.1Q (0x  
8100), length 98: vlan 5, p 0, ethertype IPv6 (0x86dd), fe80::a00:27ff:fe05:4a9e.44815 > fe80::a00:27ff  
:fea0:ff92.traceroute: UDP, length 32  
       0x0000:  0800 27a0 ff92 0800 2705 4a9e 8100 0005  ..'.....'.J.....
       0x0010:  86dd 600f ef02 0028 1101 fe80 0000 0000  ..`....(........
       0x0020:  0000 0a00 27ff fe05 4a9e fe80 0000 0000  ....'...J.......
       0x0030:  0000 0a00 27ff fea0 ff92 af0f 829a 0028  ....'..........(
       0x0040:  3117 4041 4243 4445 4647 4849 4a4b 4c4d  1.@ABCDEFGHIJKLM
       0x0050:  4e4f 5051 5253 5455 5657 5859 5a5b 5c5d  NOPQRSTUVWXYZ[\]
       0x0060:  5e5f                                     ^_
^C
2 packets captured
2 packets received by filter
0 packets dropped by kernel  
[root@bridge ~]#

Работа с VLAN

Теперь реализуем более сложную сетевую структуру с использование VLAN:

В сети будет настроено два VLAN-a. Между мостами, соединяющими абонентов из разных VLAN будет передача фреймов с тегами для отделения абонентов разных VLAN друг от друга. Получится, что физически устройства из разных VLAN достижимы, однако на программном уровне доступа друг к другу у них нет. Канал (и интерфейс, к нему присоединённый), по которому передаются фреймы разных VLAN-ов, на «инженерном» языке имеет отдельное название — «транк» (trunk), т. к. под инженерное определение VLAN не подходит.

Создадим все устройства для топологии:

hostA:
        eth1: netA
hostB:
        eth1: netB
hostD:
        eth1: netD
hostE:
        eth1: netE
bright:
        eth1: netA
        eth2: netB
        eth3: netC
bleft:
        eth1: netD
        eth2: netE
        eth3: netC

Включим все сетевые интерфейсы абонентов, таким образом получив на них IPv6-адреса. Поскольку все они находятся в разных сетях, никакой связи сейчас, естественно, между ними не будет.

hostA

[root@hostA ~]# ip link set eth1 up  
[root@hostA ~]# ip a show eth1  
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000  
   link/ether 08:00:27:2c:45:4f brd ff:ff:ff:ff:ff:ff
   altname enp0s8
   altname enx0800272c454f
   inet6 fe80::a00:27ff:fe2c:454f/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
[root@hostA ~]#

hostB

[root@hostB ~]# ip link set eth1 up  
[root@hostB ~]# ip a show eth1  
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000  
   link/ether 08:00:27:25:da:18 brd ff:ff:ff:ff:ff:ff
   altname enp0s8
   altname enx08002725da18
   inet6 fe80::a00:27ff:fe25:da18/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
[root@hostB ~]#

hostD

[root@hostD ~]# ip link set eth1 up  
[root@hostD ~]# ip a show eth1  
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000  
   link/ether 08:00:27:04:8c:e1 brd ff:ff:ff:ff:ff:ff
   altname enp0s8
   altname enx080027048ce1
   inet6 fe80::a00:27ff:fe04:8ce1/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
[root@hostD ~]#

hostE

[root@hostE ~]# ip link set eth1 up  
[root@hostE ~]# ip a show eth1  
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000  
   link/ether 08:00:27:f4:40:8a brd ff:ff:ff:ff:ff:ff
   altname enp0s8
   altname enx080027f4408a
   inet6 fe80::a00:27ff:fef4:408a/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
[root@hostE ~]#

Для мостов первоначально разберёмся с центральным каналом передачи. На нём (для обеих машин) надо настроить виртуальный интерфейс, который из eth3 будет вытягивать фреймы с соответствующим тегом:

bleft

[root@bleft ~]# ip link add link eth3 name vlan5 type vlan id 5  
[root@bleft ~]ip link add link eth3 name vlan7 type vlan id 7  

bright

[root@bright ~]# ip link add link eth3 name vlan5 type vlan id 5  
[root@bright ~]ip link add link eth3 name vlan7 type vlan id 7  

В настройках интерфейсов можно отдельно обратиться с информационным запросом к VLAN-интерфейсам:

bleft

[root@bleft ~]# ip -d link show vlan5  
6: vlan5@eth3: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default q  
len 1000  
   link/ether 08:00:27:e2:cb:22 brd ff:ff:ff:ff:ff:ff promiscuity 0 allmulti 0 minmtu 0 maxmtu 65535
   vlan protocol 802.1Q id 5 <REORDER_HDR> addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size
65536 gso_max_segs 65535 tso_max_size 65536 tso_max_segs 65535 gro_max_size 65536 gso_ipv4_max_size 655  
36 gro_ipv4_max_size 65536
[root@bleft ~]#

Теперь необходимо сложить соответствующие интерфейсы в единый мост:

Делаться это будет аналогично прошлому примеру — создаётся виртуальный интерфейс типа bridge и к нему подключаются соответствующие интерфейсы:

bleft

[root@bleft ~]# ip link add dev br5 type bridge  
[root@bleft ~]# ip link set vlan5 master br5  
[root@bleft ~]# ip link set eth1 master br5  
[root@bleft ~]# ip link add dev br7 type bridge  
[root@bleft ~]# ip link set vlan7 master br7  
[root@bleft ~]# ip link set eth2 master br7  
[root@bleft ~]#

bright

[root@bright ~]# ip link add dev br5 type bridge  
[root@bright ~]# ip link set vlan5 master br5  
[root@bright ~]# ip link set eth1 master br5  
[root@bright ~]# ip link add dev br7 type bridge  
[root@bright ~]# ip link set vlan7 master br7  
[root@bright ~]# ip link set eth2 master br7  
[root@bright ~]#

Теперь необходимо поднять все интерфейсы. Можно перебрать их руками, а можно воспользоваться циклом языка склейки, встроенном в интерпретатор shell:

bright

[root@bright ~]# ip a | grep UP | wc  
     1      13      92  # Поднят только LoopBack (по умолчанию)
[root@bright ~]# ls /sys/class/net  # Названия всех интерфейсов в системе
br5  br7  eth0  eth1  eth2  eth3  lo  vlan5  vlan7
[root@bright ~]# for I in `ls /sys/class/net`; do ip link set $I up; done  
[root@bright ~]# ip a | grep UP | wc  
     9     125     947  # Все интерфейсы подняты (даже потенциально лишние бы поднялись)
[root@bright ~]#

bleft

[root@bleft ~]# for I in `ls /sys/class/net`; do ip link set $I up; done  
[root@bleft ~]#

Заметим, что, вообще говоря, на мостах после поднятия интерфейсов создалось по 6 IPv6-адресов, по одному на каждом интерфейсе.

bright

[root@bright ~]# ip a  
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000  
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host noprefixroute
      valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 100  
0  
   link/ether 08:00:27:a3:a7:1a brd ff:ff:ff:ff:ff:ff
   altname enp0s3
   altname enx080027a3a71a
   inet6 fd17:625c:f037:2:a00:27ff:fea3:a71a/64 scope global dynamic mngtmpaddr proto kernel_ra
      valid_lft 86388sec preferred_lft 14388sec
   inet6 fe80::a00:27ff:fea3:a71a/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br5 state UP group default ql  
en 1000  
   link/ether 08:00:27:53:24:b8 brd ff:ff:ff:ff:ff:ff
   altname enp0s8
   altname enx0800275324b8
   inet6 fe80::a00:27ff:fe53:24b8/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br7 state UP group default ql  
en 1000  
   link/ether 08:00:27:92:ea:8d brd ff:ff:ff:ff:ff:ff
   altname enp0s9
   altname enx08002792ea8d
   inet6 fe80::a00:27ff:fe92:ea8d/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
5: eth3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000  
   link/ether 08:00:27:b9:eb:35 brd ff:ff:ff:ff:ff:ff
   altname enp0s10
   altname enx080027b9eb35
   inet6 fe80::a00:27ff:feb9:eb35/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
6: vlan5@eth3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br5 state UP group defau  
lt qlen 1000  
   link/ether 08:00:27:b9:eb:35 brd ff:ff:ff:ff:ff:ff
   inet6 fe80::a00:27ff:feb9:eb35/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
7: vlan7@eth3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br7 state UP group defau  
lt qlen 1000  
   link/ether 08:00:27:b9:eb:35 brd ff:ff:ff:ff:ff:ff
   inet6 fe80::a00:27ff:feb9:eb35/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
8: br5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000  
   link/ether 08:00:27:53:24:b8 brd ff:ff:ff:ff:ff:ff
   inet6 fe80::a00:27ff:fe53:24b8/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
9: br7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000  
   link/ether 08:00:27:92:ea:8d brd ff:ff:ff:ff:ff:ff
   inet6 fe80::a00:27ff:fe92:ea8d/64 scope link proto kernel_ll
      valid_lft forever preferred_lft forever
[root@bright ~]#

Проверим работоспобность сети: hostA должен достигать hostD, hostB должен достигать hostE и больше никто никого достигать не должен:

hostA

[root@hostA ~]# traceroute -q1 -m1 fe80::a00:27ff:fe04:8ce1%eth1
traceroute to fe80::a00:27ff:fe04:8ce1%eth1 (fe80::a00:27ff:fe04:8ce1%eth1), 1 hops max, 80 byte packe
ts  
1  fe80::a00:27ff:fe04:8ce1%eth1 (fe80::a00:27ff:fe04:8ce1%eth1)  1.379 ms
[root@hostA ~]# traceroute -q1 -m1 fe80::a00:27ff:fe25:da18%eth1
traceroute to fe80::a00:27ff:fe25:da18%eth1 (fe80::a00:27ff:fe25:da18%eth1), 1 hops max, 80 byte packe
ts  
1  hostA (fe80::a00:27ff:fe2c:454f%eth1)  3077.218 ms !H
[root@hostA ~]# traceroute -q1 -m1 fe80::a00:27ff:fef4:408a%eth1
traceroute to fe80::a00:27ff:fef4:408a%eth1 (fe80::a00:27ff:fef4:408a%eth1), 1 hops max, 80 byte packe
ts  
1  hostA (fe80::a00:27ff:fe2c:454f%eth1)  3109.389 ms !H
[root@hostA ~]#

hostB

[root@hostB ~]# traceroute -q1 -m1 fe80::a00:27ff:fef4:408a%eth1
traceroute to fe80::a00:27ff:fef4:408a%eth1 (fe80::a00:27ff:fef4:408a%eth1), 1 hops max, 80 byte packe
ts  
1  fe80::a00:27ff:fef4:408a%eth1 (fe80::a00:27ff:fef4:408a%eth1)  1.663 ms
[root@hostB ~]# traceroute -q1 -m1 fe80::a00:27ff:fe04:8ce1%eth1
traceroute to fe80::a00:27ff:fe04:8ce1%eth1 (fe80::a00:27ff:fe04:8ce1%eth1), 1 hops max, 80 byte packe
ts  
1  hostB (fe80::a00:27ff:fe25:da18%eth1)  3106.539 ms !H
[root@hostB ~]# traceroute -q1 -m1 fe80::a00:27ff:fe2c:454f%eth1
traceroute to fe80::a00:27ff:fe2c:454f%eth1 (fe80::a00:27ff:fe2c:454f%eth1), 1 hops max, 80 byte packe
ts  
1  hostB (fe80::a00:27ff:fe25:da18%eth1)  3101.267 ms !H
[root@hostB ~]#

При этом соответствующие интерфейсы на мостах отлавливают только свои и ничьи другие фреймы:

bright

[root@bright ~]# tcpdump -XXei br5 udp  
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode  
listening on br5, link-type EN10MB (Ethernet), snapshot length 262144 bytes  
10:25:34.767335 08:00:27:2c:45:4f (oui Unknown) > 08:00:27:04:8c:e1 (oui Unknown), ethertype IPv6 (0x86  
dd), length 94: fe80::a00:27ff:fe2c:454f.39517 > fe80::a00:27ff:fe04:8ce1.traceroute: UDP, length 32  
       0x0000:  0800 2704 8ce1 0800 272c 454f 86dd 6007  ..'.....',EO..`.
       0x0010:  0487 0028 1101 fe80 0000 0000 0000 0a00  ...(............
       0x0020:  27ff fe2c 454f fe80 0000 0000 0000 0a00  '..,EO..........
       0x0030:  27ff fe04 8ce1 9a5d 829a 0028 be3e 4041  '......]...(.>@A
       0x0040:  4243 4445 4647 4849 4a4b 4c4d 4e4f 5051  BCDEFGHIJKLMNOPQ
       0x0050:  5253 5455 5657 5859 5a5b 5c5d 5e5f       RSTUVWXYZ[\]^_

bleft

[root@bleft ~]# tcpdump -XXei eth3 udp  
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode  
listening on eth3, link-type EN10MB (Ethernet), snapshot length 262144 bytes  
10:25:33.288444 08:00:27:2c:45:4f (oui Unknown) > 08:00:27:04:8c:e1 (oui Unknown), ethertype 802.1Q (0x  
8100), length 98: vlan 5, p 0, ethertype IPv6 (0x86dd), fe80::a00:27ff:fe2c:454f.39517 > fe80::a00:27ff  
:fe04:8ce1.traceroute: UDP, length 32  
       0x0000:  0800 2704 8ce1 0800 272c 454f 8100 0005  ..'.....',EO....
       0x0010:  86dd 6007 0487 0028 1101 fe80 0000 0000  ..`....(........
       0x0020:  0000 0a00 27ff fe2c 454f fe80 0000 0000  ....'..,EO......
       0x0030:  0000 0a00 27ff fe04 8ce1 9a5d 829a 0028  ....'......]...(
       0x0040:  be3e 4041 4243 4445 4647 4849 4a4b 4c4d  .>@ABCDEFGHIJKLM
       0x0050:  4e4f 5051 5253 5455 5657 5859 5a5b 5c5d  NOPQRSTUVWXYZ[\]
       0x0060:  5e5f                                     ^_

Фильтрация тегов на уровне моста

Во всех наших примерах мы использовали интерфейс bridge исключительно для связывания интерфейсов. Сама фильтрация VLAN осуществляется при проходе пакета через соответствующий интерфейс.

Сам сетевой мост — это достаточно ёмкое по технологиям устройство. Одна только поддержка STP требует внутреннего отслеживания и обработки пакетов для поддержания корректного остовного дерева. Поэтому неудивительно, что сам bridge-интерфейс умеет отслеживать VLAN-метки. Пример такой настройки и управления 802.1Q-фреймами представлен в лабораторных работах на эту тему (на Usamg1t.Github.io или в документации «Базальт СПО»).

Домашнее задание: