Построение виртуального свитча из нескольких сетевых карт с использованием Netgraph [2009]
Итак
Виртуальный свич из нескольких сетевух на нетграфе.
Ситуация такая:
на сервере интерфейс rl0 смотрит наружу, в локалку провайдера 10.*.*.*.
а vr0 и vr1 смотрят во внутреннюю сеть 192.168.0.*
Для удобства хотелось бы чтобы в домашнюю сеть смотрела одна сетевуха,
а все компы домашней сети были подключены к серверу через свич.
Реализуем задуманное на основе ядерного модуля ng_bridge!
Кому лень читать статью полностью, выкладываю свой скрипт.
Скрипт предоставляется "As Is" - что то тут лишнее, что то кривое...
Конструктивная критика приветствуется. Наличие необходимых зависимостей
подразумевается.
;; *) if [ -s $PidFile ]; then ${Echo} State: Up else ${Echo} State: Down fi
;; esac
Нетграф по слухам чертовски производителен и чертовски плохо
документирован, особенно на русском, так что если что не так, не
обессудьте - в описанной конфигурации у меня все работает уже не один
месяц. Также оговорюсь, что все беру с рабочей системы, так что может
быть что от лишнее, а чего то может не хватать.
Начнем с необходимого - с нетграфа. Вот список того, что стоит у меня:
Как видно из всего этого необходим минимум ng_eiface, который я
забыл(или поленился) положить в ядро. Кроме того нам понадобятся модули
ng_ether и ng_bridge. Но никто не запрещает побаловаться с ng_tee,
ng_ipfw и чем нить подобным для подсчета трафика, шейпинга et cetera...
После загрузки модулей нужных модулей смотрим что мы имеем
# ngctl list There are 6 total nodes: Name: <unnamed> Type: eiface ID: 0000001e Num hooks: 0 Name: rl0 Type: ether ID: 00000001 Num hooks: 0 Name: vr0 Type: ether ID: 00000002 Num hooks: 0 Name: vr1 Type: ether ID: 00000003 Num hooks: 0 Name: ngeth0 Type: ether ID: 00000003 Num hooks: 0 Name: ngctl38473 Type: socket ID: 0000be26 Num hooks: 0
Мы должны видеть узлы типа ether по числу реальных интерфейсов,
виртуальный интерфейс ngeth0 и соответствующий ему и узел socket,
который служит для связи ngctl с ядром(это уже мои измышления.
Подробнее - man ng_socket && man ngctl). Еще мы видем один
безымянный узел - это родственник ngeth0, они создаются и уничтожаются
только вместе.
Далее нам надо сделать мост. Но просто так его нельзя создать, его надо на что то прицепить. Прицепим хук link0 к хуку lower сетевухи vr0. Сказано - сделано. Попутно обзовем его каким нибудь нехорошим именем, типа switch
Вот тут надо остановиться и поподробнее рассказать что такое
хуки(hooks), узлы(nodes), какие они бывают и с чем их едят. Нетграф -
это система, которая строит граф, по которому бегают данные. В графе
есть узлы и ребра. Иногда узел может просто висеть в воздухе(как
например узлы наших сетевух), но чаще чтобы добавить какой то узел надо
его к чему ни будь прикрутить. Прикручивание происходит соединением
хуков разных узлов. После соединения между хуками появляется ребро по
которому могут бегать данные от одного узла к другому. Хуки бывают
разные и у каждого типа узла они свои. Какие то пропускают пакеты
только в одну сторону, какие то пускают только пакеты верхних сетевых
протоколов, подробнее про типы узлов написано в манах, а пока про
насущное. У сетевух(узлов типа ether) есть три хука - upper,
lower, и orphans. Грубо говоря, lower работает с нижними
протоколами(ethernet), upper - с верхними, а про orphans не помню, но
он мне не вроде не подошел. У bridge - до NG_BRIDGE_MAX_LINKS(у меня на
7.2 в src/sys/netgraph/ng_bridge.h:55 говорится про 32 хука) хуков с
именами типа link0 link1 link2... У eiface только один хук - ether
через который бегают все пакеты.
При обращении к локальным узлам пишем двоеточие в конце имени.
Обращаться можно как по имени, так и по ID. в последнем случае вместо <node_name>: пишется [0x<node_id>]:
С теорией вроде закончил, перейдем к практике. Продолжаем строит свич: цепляем к мосту остальные хуки сетевушек
Идем далее. Сетевухи имеют свойства выпуская пакет прописывать в нем
поле отправитель себя и игнорировать пакеты, предназначенные не ей.
Отучаем их от этих нехороших привычек:
И далее самое интересное. снимаем ипы с реальных сетевух(порты свича
не имеют ипов) и ставим внутренний ип(у меня это 192.168.0.1) машины на
виртуальную сетевуху. Реальные карточки должны быть без ипов только в
состояниии UP
# ifconfig rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=8<VLAN_MTU> ether <XXX> inet 10.XXX.XXX.XXX netmask 0xffffXXX broadcast 10.XXX.XXX.XXX media: Ethernet autoselect (100baseTX <full-duplex>) status: active vr0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=2808<VLAN_MTU,WOL_UCAST,WOL_MAGIC> ether <XXX> media: Ethernet autoselect (100baseTX <full-duplex>) status: active vr1: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=2808<VLAN_MTU,WOL_UCAST,WOL_MAGIC> ether <XXX> media: Ethernet autoselect (100baseTX <full-duplex>) status: active ngeth0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 ether 00:00:00:00:00:00 inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255 <overquoting deleted> # ngctl list There are 17 total nodes: Name: <unnamed> Type: ksocket ID: 0000be23 Num hooks: 1 Name: <unnamed> Type: pptpgre ID: 0000be22 Num hooks: 2 Name: <unnamed> Type: eiface ID: 0000001e Num hooks: 1 Name: ng0 Type: iface ID: 0000bd94 Num hooks: 1 Name: rl0 Type: ether ID: 00000001 Num hooks: 0 Name: switch Type: bridge ID: 00000014 Num hooks: 5 Name: vr0 Type: ether ID: 00000002 Num hooks: 2 Name: vr1 Type: ether ID: 00000003 Num hooks: 2 Name: mpd16513-stats Type: socket ID: 0000bd9a Num hooks: 0 Name: ngctl38842 Type: socket ID: 0000be2a Num hooks: 0 Name: mpd16513-cso Type: socket ID: 0000bd92 Num hooks: 0 Name: mpd16513-eso Type: socket ID: 0000bd93 Num hooks: 0 Name: mpd16513-lso Type: socket ID: 0000bd91 Num hooks: 1 Name: ngeth0 Type: ether ID: 0000001f Num hooks: 0 Name: mpd16513-B1-mss Type: tcpmss ID: 0000be24 Num hooks: 2 Name: mpd16513-B1 Type: ppp ID: 0000bd95 Num hooks: 3 Name: mpd16513-L1-lt Type: tee ID: 0000bd96 Num hooks: 2
# arp -a ? (10.XXX.XXX.XXX) at <XXX_MAC> on rl0 [ethernet] ------------------------``---------------------------------- ? (192.168.0.2) at <XXX_MAC> on ngeth0 [ethernet] ? (192.168.0.3) at <XXX_MAC> on ngeth0 [ethernet] ? (192.168.0.255) at ff:ff:ff:ff:ff:ff on ngeth0 permanent [ethernet]
Примечание: записи вида ? (10.XXX.XXX.XXX) at <XXX_MAC> on rl0 [ethernet] - адреса из локалки провайдера)
Как видно, сетевухи vrX смирились со своей ролью в качестве
портов свича и на них не висят маки соседих машин. Все выглядит так,
будто у нас есть свич, в который воткнуты кабеля машин внутренней сети
и кабель от нашего компа с интерфейса ngeth0(любопытно, что ifconfig и
arp по разному определяют его мак). самого свича, как и полагается, не
видно
Дальше разруливаем все пакеты файером, в нем разрешаем
прохождение пакетов через реальные внутренние сетевухи(или шейпим/режем
по надобности), ставим нат с внешней сетевухи на ngeth0, раздача инета
между сетевухами моста будет регулироваться нетграфом. В общем ведем
себя так, как будто у нас появился свич и исчезли две сетевухи.