Делаем «router-on-a-stick» в linux namespaces

Не буду томить вам долгим вступлением. Ниже подробное описание этой реализации.

xraoancc2g0d6hn46ks88r7vu_c.png
Все команды выполняем от рута.


Создание неймспейсов и виртуальных интерфейсов

Создадим неймспейсы ns10, ns20, ns30 в качестве клиентов, бридж (коммутатор) разместим в неймспейсе nsbridge, рутер в неймспейсе nsrouter. Создадим пары виртуальных интерфейсов veth10 — veth11, veth20 — veth21, veth 30 — veth31, одну сторону пары заведем в неймспейсы ns10 — 30, вторую в nsbridge. Бридж и рутер соединим еще одной парой интерфейсов vethbr — vethrou.

# создаем неймспейсы
ip netns add ns10
ip netns add ns20
ip netns add ns30
ip netns add nsbridge
ip netns add nsrouter

# создаем интерфейсы
ip link add name veth10 type veth peer name veth11
ip link add name veth20 type veth peer name veth21
ip link add name veth30 type veth peer name veth31
ip link add name vethbr type veth peer name vethrou

# заводим интерфейсы в неймспейсы
ip link set dev veth10 netns ns10  
ip link set dev veth20 netns ns20
ip link set dev veth30 netns ns30

ip link set dev veth11 netns nsbridge
ip link set dev veth21 netns nsbridge
ip link set dev veth31 netns nsbridge
ip link set dev vethbr netns nsbridge

ip link set dev vethrou netns nsrouter

# включаем интерфейсы
ip netns exec ns10 ip link set dev lo up
ip netns exec ns10 ip link set dev veth10 up
ip netns exec ns20 ip link set dev lo up
ip netns exec ns20 ip link set dev veth20 up
ip netns exec ns30 ip link set dev lo up
ip netns exec ns30 ip link set dev veth30 up

ip netns exec nsbridge ip link set dev lo up
ip netns exec nsbridge ip link set dev veth11 up
ip netns exec nsbridge ip link set dev veth21 up
ip netns exec nsbridge ip link set dev veth31 up
ip netns exec nsbridge ip link set dev vethbr up

ip netns exec nsrouter ip link set dev lo up
ip netns exec nsrouter ip link set dev vethrou up


Настройка коммутации

Интерфейсы, ведущие в ns10 и ns20, поместим в один vlan 10. Интерфейс, ведущий в ns30, поместим в vlan 30. Тогда ns10 и ns20 будут находиться в одном широковещательном домене и смогут общаться друг с другом и без использования рутера.

ns30 будет в отдельном широковещательном домене и сможет общаться с ns10 и ns20 только через маршрутизацию на рутере (где можно вводить определенные ограничения на такой доступ).

Заведенные в nsbridge интерфейсы veth11, veth21, veth31 подсоединим к бриджу в режиме access. Назначим vlan id 10 на veth11 и veth21, и vlan id 30 на veth31. Интерфейс vethbr подключим в режиме trunk и разрешим ему пропускать vlan 10 и 30.

# создаем бридж и включаем его
ip netns exec nsbridge ip link add name br type bridge
ip netns exec nsbridge ip link set dev br up

# переводим бридж в режим VLAN-aware
ip netns exec nsbridge ip link set dev br type bridge vlan_filtering 1

# подключаем к нему интерфейсы
ip netns exec nsbridge ip link set dev veth11 master br
ip netns exec nsbridge ip link set dev veth21 master br
ip netns exec nsbridge ip link set dev veth31 master br
ip netns exec nsbridge ip link set dev vethbr master br

# устанавливаем режим access на veth11, veth21, veth31
ip netns exec nsbridge bridge vlan add vid 10 dev veth11 pvid untagged
ip netns exec nsbridge bridge vlan add vid 10 dev veth21 pvid untagged
ip netns exec nsbridge bridge vlan add vid 30 dev veth31 pvid untagged

# устанавливаем режим trunk на vethbr
ip netns exec nsbridge bridge vlan add dev vethbr vid 10
ip netns exec nsbridge bridge vlan add dev vethbr vid 30

# присваиваем ip адреса
ip netns exec ns10 ip addr add 192.168.10.2/24 dev veth10
ip netns exec ns20 ip addr add 192.168.10.3/24 dev veth20
ip netns exec ns30 ip addr add 192.168.30.2/24 dev veth30

# и дефолтные маршруты через маршрутизатор
ip netns exec ns10 ip r add default via 192.168.10.1
ip netns exec ns20 ip r add default via 192.168.10.1
ip netns exec ns30 ip r add default via 192.168.30.1


Рутер

Создание рутера заключается в создании vlan интерфейсов на основе интерфейса, соединяющего рутер и бридж, присваивания им ip адресов и включения форвардинга пакетов между vlan интерфейсами.

# создаем vlan интерфейсы и включаем их
ip netns exec nsrouter ip link add link vethrou name vethrou.10 type vlan id 10
ip netns exec nsrouter ip link add link vethrou name vethrou.30 type vlan id 30
ip netns exec nsrouter ip link set dev vethrou.10 up
ip netns exec nsrouter ip link set dev vethrou.30 up

# присваиваем им адреса
ip netns exec nsrouter ip addr add 192.168.10.1/24 dev vethrou.10
ip netns exec nsrouter ip addr add 192.168.30.1/24 dev vethrou.30

# включаем форвардинг пакетов между интерфейсами
ip netns exec nsrouter sysctl -w net.ipv4.ip_forward=1


Проверка

Проверяем связность между неймспейсами:

пинг между ns10 и ns20

ip netns exec ns10 ping 192.168.10.3
---
PING 192.168.10.3 (192.168.10.3) 56(84) bytes of data.
64 bytes from 192.168.10.3: icmp_seq=1 ttl=64 time=0.123 ms
64 bytes from 192.168.10.3: icmp_seq=2 ttl=64 time=0.110 ms

пинг между ns10 и ns30

ip netns exec ns10 ping 192.168.30.2
---
PING 192.168.30.2 (192.168.30.2) 56(84) bytes of data.
64 bytes from 192.168.30.2: icmp_seq=1 ttl=63 time=0.199 ms
64 bytes from 192.168.30.2: icmp_seq=2 ttl=63 time=0.151 ms

смотрим трафик на коммутаторе

ip netns exec nsbridge tcpdump -i vethbr -n -e -v
---
# пакет с ns10 на рутер. виден vlan10
09:26:42.066162 5e:b0:da:5a:95:76 > 3a:02:15:e3:44:d1, ethertype 802.1Q (0x8100), length 102: vlan 10, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 4537, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.10.2 > 192.168.30.2: ICMP echo request, id 43125, seq 1, length 64
# пакет с рутера на ns30. виден vlan30
09:26:42.066206 3a:02:15:e3:44:d1 > f6:df:30:1a:96:7e, ethertype 802.1Q (0x8100), length 102: vlan 30, p 0, ethertype IPv4, (tos 0x0, ttl 63, id 4537, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.10.2 > 192.168.30.2: ICMP echo request, id 43125, seq 1, length 64
# пакет с ns30 на рутер (vlan 30)
09:26:42.066233 f6:df:30:1a:96:7e > 3a:02:15:e3:44:d1, ethertype 802.1Q (0x8100), length 102: vlan 30, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 20169, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.30.2 > 192.168.10.2: ICMP echo reply, id 43125, seq 1, length 64
# пакет с рутера на ns10 (vlan 10)
09:26:42.066238 3a:02:15:e3:44:d1 > 5e:b0:da:5a:95:76, ethertype 802.1Q (0x8100), length 102: vlan 10, p 0, ethertype IPv4, (tos 0x0, ttl 63, id 20169, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.30.2 > 192.168.10.2: ICMP echo reply, id 43125, seq 1, length 64

запускаем в ns30 веб-сервер и обращаемся к нему из ns10, все работает

ip netns exec ns30 python3 -m http.server &
ip netns exec ns10 curl -v 192.168.30.2:8000

отключаем net.ipv4.ip_forward на рутере

ip netns exec nsrouter sysctl -w net.ipv4.ip_forward=0

тогда пинг между ns10 и ns20 проходит, т.к. они в одном vlan (пакеты идут через коммутатор без участия рутера)

ip netns exec ns10 ping 192.168.10.3
---
PING 192.168.10.3 (192.168.10.3) 56(84) bytes of data.
64 bytes from 192.168.10.3: icmp_seq=1 ttl=64 time=0.136 ms
64 bytes from 192.168.10.3: icmp_seq=2 ttl=64 time=0.112 ms

а пинг между ns10 и ns30 не проходит, т.к. рутер выключен

ip netns exec ns10 ping 192.168.30.2 -c 2
---
PING 192.168.30.2 (192.168.30.2) 56(84) bytes of data.
^C
--- 192.168.30.2 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1027ms


Добавляем внешний интернет

Добавим пару виртуальных интерфейсов veth1 — veth2. veth1 оставим в основном неймспейсе, veth2 перенесем в nsrouter

ip link add name veth1 type veth peer name veth2
ip link set dev veth2 netns nsrouter
ip link set dev veth1 up
ip addr add 10.10.10.1/24 dev veth1
ip netns exec nsrouter ip link set dev veth2 up
ip netns exec nsrouter ip addr add 10.10.10.2/24 dev veth2

В основном неймспейсе добавим трансляцию ip адреса источника на адрес выходного интерфейса enp1s0 для пакетов из veth1 и включим форвардинг пакетов между интерфейсами

iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o enp1s0 -j MASQUERADE
sysctl -w net.ipv4.ip_forward=1

В неймспейсе рутера также добавим маршрут по умолчанию и трансляцию ip адресов

ip netns exec nsrouter ip r add default via 10.10.10.1
ip netns exec nsrouter iptables -t nat -A POSTROUTING  -s 192.168.0.0/16 -o veth2 -j MASQUERADE

Теперь внешний интернет доступен в ns10 — ns30

ip netns exec ns30 ping 8.8.8.8 -c 2
---
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=102 time=138 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=102 time=160 ms

Спасибо за внимание.

© Habrahabr.ru