В ядре Linux(начиная с версии 2.6.29) имеется весьма интересный и полезный функционал network namespaces(netns), однако про его существование, чаще всего, либо не знают, либо не понимают что с ним можно делать. В этой заметке рассматривается несколько примеров применения этого функционала:
- Мониторинг L3VPN с пересекающимися адресными пространствами средствами zabbix и zabbix-proxy
- Автоматизированное тестирование сетевого ПО(dhcp, pppoe-сервера и т.п.)
- Предоставление услуги L3VPN с дополнительными сервисами(NAT, DHCP и другими) и виртуализация абонентской CPE как частный случай решения этой задачи
- Изоляция управления сервером от остальных сервисов
Функционал похож на Cisco VRF, но ещё больше напоминает Juniper logical-system. Кроме того, описываемые задачи можно решать с помощью создания множества обычных виртуальных машин или контейнеров OpenVZ. Традиционная виртуализация не очень удобна для “чисто сетевых” задач “изоляции” и так или иначе, имеет накладные расходы(в том числе на обслуживание). OpenVZ почти всем хорош, кроме того, что не закоммичен в апстрим и как следствие ограничивает вас в выборе ядра, привязывает к себе(тянет себя как зависимость).
Для написания этой заметки использовался дистрибутив Ubuntu 12.04.2 LTS, однако почти всё применимо и для большинства других современных дистрибутивов. Прежде чем пытаться что-то сделать, нужно проверить наличие netns в ядре и поддержку сетевых пространств в userspace-утилите ip, которая используется для конфигурирования:
# cat /boot/config-`uname -r` | grep CONFIG_NET_NS CONFIG_NET_NS=y # ip netns help Usage: ip netns list ip netns add NAME ip netns delete NAME ip netns exec NAME cmd ... ip netns monitor
Каждый netns это свои интерфейсы, таблицы маршрутизации, свой фаервол и собственные сокеты, изолированные от других netns. Для простоты изложения, первым примером будет демонстрация как netns можно использовать для автоматизированного тестирования сетевого ПО(создающее интерфейсы, маршруты и т.п.) на примере pppoe-сервера accel-pppd. Схема тестирования:
В первую очередь, создаём 2 netns и 2 виртуальных ethernet интерфейса(привязанные к разным netns) и связываем их между собой линком:
#Создание 2ух netns: ip netns add Server ; ip netns add Client #Создание 2ух veth-интерфейса и линка между ними ip link add veth0-C type veth peer name veth0-S #Привязка интерфейсов к своим netns: ip link set veth0-C netns Client ip link set veth0-S netns Server #Поднятие интерфейсов(ifconfig выполняется уже в разных netns): ip netns exec Client ifconfig veth0-C up ip netns exec Server ifconfig veth0-S up
Таким образом, получили L2-связность между двумя netns, при этом оба netns изолированы от глобального. Далее запускаем сервер и клиент, каждый в своём сетевом пространстве:
ip netns exec Server /etc/init.d/accel-ppp start ip netns exec Client pppd call test1
Конфигурация /etc/accel-ppp.conf (авторизовываться можно с любым логином/паролем). Конфигурацию клиента(/etc/ppp/peers/test1 ) можно сгенерировать командой “ip netns exec Client pppoeconf”.
Результат:
# ip netns exec Client ip route show default dev ppp0 scope link 192.0.2.1 dev ppp0 proto kernel scope link src 192.0.2.2 # ip netns exec Server ip route show 192.0.2.2 dev ppp0 proto kernel scope link src 192.0.2.1 # ip netns exec Client ping 192.0.2.1 -c 1 PING 192.0.2.1 (192.0.2.1) 56(84) bytes of data. 64 bytes from 192.0.2.1: icmp_req=1 ttl=64 time=0.155 ms ...
Как видно, pppoe-сессия установлена, созданные интерфейсы и маршруты никому не мешают, т.к. не попали в namespace по умолчанию. Аналогичным образом можно тестировать dhcp/l2tp/openvpn/прочие сервисы в пределах одного хоста, что в свою очередь позволяет легко автоматизировать процесс тестирования, потому что нет никаких препятствий, чтобы написать скрипт, создающий netns-ы, интерфейсы и запускающий в них процессы(сервер и клиент(ы)). Для проведения тестов не нужно привязываться к стороннему ПО типа openvz или vmware и писать сложные скрипты, чтобы ими управлять.
Вторым примером будет использование netns и zabbix+zabbix proxy для мониторинга нескольких vrf/l2vpn с пересекающимися адресными пространствами.
Через eth0.10 и eth0.20 осуществляется выход в клиентские vrf, через veth-интерфейсы реализуется связность между глобальным netns(в котором запущен zabbix-server) и процессами zabbix-proxy. Через интерфейс eth0(или eth1) организовано управлением сервером.
#Создание 2ух netns ip netns add vrf1; ip netns add vrf2 #Создание 2ух dot1Q сабынтерфейсов vconfig add eth0 10; vconfig add eth0 20 #Привязка сабынтерфейсов к своим netns ip link set eth0.10 netns vrf1 ip link set eth0.20 netns vrf2 #Назначение IP-адреса и указание шлюза для доступа в клиентские vpn ip netns exec vrf1 ifconfig eth0.10 192.0.2.2/30 up ip netns exec vrf2 ifconfig eth0.20 192.0.2.2/30 up ip netns exec vrf2 ip route add default via 192.0.2.1 ip netns exec vrf1 ip route add default via 192.0.2.1 #Связность между vrf1 и глобальным netns ip link add veth1-P type veth peer name veth1-S; ip link set veth1-P netns vrf1 ifconfig veth1-S add 2001:DB8::1/126 up ip netns exec vrf1 ifconfig veth1-P add 2001:DB8::2/126 #Связность между vrf2 и глобальным netns ip link add veth2-P type veth peer name veth2-S; ip link set veth2-P netns vrf1 ifconfig veth2-S add 2001:DB8::5/126 up ip netns exec vrf1 ifconfig veth2-P add 2001:DB8::6/126 #Запуск zabbix-ов /etc/init.d/zabbix-server start ip netns exec vrf1 zabbix_proxy1_start ip netns exec vrf2 zabbix_proxy2_start
Очевидно, что адресация на veth-линках не должна пересекаться, в примере используются ipv6-адреса (чтобы не согласовывать эти адреса со всеми клиентами и не использовать реальные IPv4-адреса). Адреса на “внешних” интерфейсах eth0.10 и eth0.20 нужно согласовывать с клиентами, но они могут пересекаться, проще говоря, нужно всего лишь попросить клиента выделить любую /30 из его адресного плана (или сделать это самостоятельно, если это ваш технологический vpn).
Настройка самого zabbix выходит за рамки этой заметки, но принципиальных отличий от схемы с множеством хостов нет (за исключением того, что на одном сервере будет несколько конфигураций и скриптов запуска zabbix-proxy)
Далее пойдёт речь об организации L3VPN с дополнительными сервисами(DHCP-сервер и интернет через NAT)
В сетевом пространстве Client1 интерфейс eth0.10 используется для выхода в интернет, интерфейсы eth0.11-eth0.19 смотрят в точки подключения клиента(на каждую точку подключения выделяется свой vlan). Выделение реальных адресов осуществляется по схеме ip unnumbered. В данном примере это реализуется на маршрутизаторе ASBR. Как настроить ip unnumbered со статическим распределением адресов на Cisco или Linux можно без проблем найти на просторах интернета. Если же роль ASBR-а выполняет сам сервер(на котором реализуются абонентские vpn), то тогда роль интерфейсов eth0.10 и eth0.20 будут играть veth-интерфейсы(между netns клиента и глобальным netns), а ip unnumbered будет реализован на этом же хосте в сетевом пространстве по умолчанию.
Включение маршрутизации и NAT осуществляется следующим образом:
ip netns exec Client1 sysctl net.ipv4.ip_forward=1 ip netns exec Client1 iptables -t nat -I POSTROUTING -o eth0.10 -j SNAT --to-source 192.0.2.2 ip netns exec Client2 sysctl net.ipv4.ip_forward=1 ip netns exec Client2 iptables -t nat -I POSTROUTING -o eth0.20 -j SNAT --to-source 192.0.2.3
Остальные необходимые действия(создание netns и назначение адресов) рассматривались в первых двух примерах. При необходимости можно предоставлять клиентам DHCP-сервис, для этого нужно запустить dhcpd в соответствующем netns. Если клиент хочет bgp в своём vpn, то можно запустить quagga/bird в его netns.
Нетрудно догадаться, что в случае, когда клиенсткая точка одна, то решение этой задачи будет представлять ни что иное как виртуализация абонентской CPE(или как сейчас модно говорить, облачная CPE). Такой вариант может быть интересен для предоставление сервиса высокодоходным клиентам, для массового же сервиса не имеет смысла выделять netns под каждого клиента, а просто выделять клиентам различные серые сети(из диапазона RFC6598) в одном сетевом пространстве.
Заключительным примером использования будет перенос управления сервером в неглобальный netns.
/etc/init.d/ssh stop ip netns exec MGMT /usr/sbin/sshd -D
Теперь, подключившись по ssh к этому серверу вы окажитесь в сетевом пространстве MGMT(выполнив ifconfig будут отображаться интерфейсы, относящиеся только к netns MGMT). Можно “перейти” в любой другой netns таким образом: “ip netns exec Other-ns bash”, но не в глобальный. Чтобы выбраться в глобальный netns придётся скомпилировать утилиту ns_exec из документации к функции setns(man setns)(копия исходника ns_exec.c)
gcc ns_exec.c -o ns_exec #Использование ns_exec: ./ns_exec /proc/1/ns/net bash
(где 1 – номер процесса init)
P.S. При создании нового netns, в нём не поднят интерфейс-петля(lo), будьте внимательны. Из-за этого не работает ping локальных IP-адресов(назначенных на интерфейсах) из самого netns. Чтобы поднять loopback, нужно выполнить “ip netns exec NS ifconfig lo 127.0.0.1 up”
Отличная статья!
Pingback: Burst vs буфер коммутации | Net-Labs.in
Pingback: VRF (L3VPN) в Mikrotik RouterOS: defective by design | Net-Labs.in
Pingback: Linux Network Namespaces: Examples of Usage | Net-Labs.in
Pingback: Маршрутизация multicast в Linux (IGMPv3 и IGMPv2) | Net-Labs.in