Книги, научные публикации

1 Modern Linux - network virtualizing Москва май 2006 Алексей Барабанов.

Современный Linux сервер : виртуализация сетевых устройств.

В серверном эксплуатационном цикле часто возникает потребность во всевозможных манипуляциях над сетевыми подключениями в режиме on-line. Переведя последние в категорию виртуальных можно значительно упростить их обслуживание и предусмотреть многие внештатные ситуации.

Введение.

Сетевые интерфейсы в серверах обычно ассоциируются с чем-то неизменным и предопределенным. Их число, топология подключения и настройки, как правило, заранее определяются в проектном задании и не меняются в процессе штатной эксплуатации. Но даже в таком идеальном или, что вернее, идеализированном рассуждении статичность интерфейсов весьма условна. Возможен и иной взгляд на подсистему, отвечающую за сетевые интерфейсы. Безусловно, это всего лишь некий технический прием или рекомендация и каждый волен следовать ей или предпочесть ортодоксальный вариант настроек. Более того, и не откровение, так как элементы такого подхода можно встретить во многих системах, например во встроенных Linux или при создании виртуальных серверов. Далее рассмотрим последовательно основания, идею и реализацию перевода сетевых интерфейсов в виртуальный режим. В качестве платформы будем использовать openSUSE Linux версии 10.0 и 10.1 [1], указывая на несовместимости и различия. Итак, начнем с перечисления возможных проблем, не решаемых в рамках традиционной настройки сети.

Основания.

Рассмотрим редкий вариант, когда в сервере всего лишь один сетевой интерфейс. Что тут сложного - спрашивается, - от рождения и до смерти будет eth0. А вот и нет, как бы того не хотелось многим наивным скриптописателям, eth0 будет лишь в идеальном случае при установке системы прямо на данный системный блок. Если же, что более реально, сервер не устанавливается каждый раз с нуля, а портируется через образ системы или всего жесткого диска, то, скорее всего, даже единственный интерфейс будет иметь иное название, eth1 и далее, в том случае, если полагаться на автоматическую систему наименования устройств, использованную в udev, что для современных систем является стандартом.

Но в серверах, как правило, более одного интерфейса. И если их названия в некоторый момент упорядочены и устраивают системного администратора и использованные им настроечные скрипты, то представим, что может произойти в случае отказа одного из интерфейсов. Например, произошел отказ в процессе старта. В старых системах, без использования udev, происходило смещение нумерации устройств или фактическая перекоммутация соединений. Интерфейсы, предназначенные для внутресетевых соединений, могли переключиться на внешние линии. Практически, это означало крах всей системы защиты. Современные скрипты, ориентированные на udev, привязывают имена 2 Modern Linux - network virtualizing сетевых интерфейсов к их физическим адресам или pci-идентификаторам. Можно быть уверенным, что катастрофического выворачивания сервера внутренними интерфейсами наружу не произойдет. Но есть иная беда. Сетевая конфигурация, созданная автоматическим образом, может потерять свое сбалансированное состояние, и очередная перезагрузка может привести к новому изменению имен интерфейсов из-за отказа одной из сетевых карт. Впрочем, и при добавлении сетевой карты в систему с udev такие случаи нередки. Итогом подобного процесса может стать частичный или полный отказ стартовых сетевых скриптов, то есть изоляция сервера от сети. Для противодействия этому в системах с udev рекомендуется применять постоянные или персистентные (от persistent - постоянный) сетевые имена. Увы, в такой схеме главное исключить столкновение переименований. Другими словами, сетевые интерфейсы могут называть как угодно, но только не по схеме ethN, принятой по умолчанию.

Выход из строя сетевой карты непосредственно в ходе эксплуатации потребует замены физического интерфейса, то есть в процессе очередного старта произойдет добавление следующего номера в базу udev при обнаружении нового устройства, что сведется к ранее описанной проблеме привязки имен. Но можно и рассмотреть существование в серверном блоке сетевой карты, рассчитанной на горячую замену. Тут мы сталкиваемся с иной сложностью. Простое отключение интерфейса через ifdown (как вариант через ip link set) может привести к нарушению работы сетевых служб использующих (прослушивающих) адрес данного интерфейса. Это в том благоприятном случае, если Вы уверены, что созданная на лету аварийная схема при следующем рестарте не сломается.

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

Теперь пример из смежной области. Давайте задумаемся о том, как производится включение сетевого экрана в процессе старта сервера. Самый грамотный, из мною наблюдаемых, это способ, использованный в дистрибутивах SuSE. Безусловно, в качестве серьезного решения это совершенно неприемлемо (практически бытовой вариант).

Отметим лишь одно важное качество, в этом сетевом экране выделена отдельная стадия предварительной настройки - сначала срабатывает SuSEfirefall2_init после старта boot.localnet, а потом уже SuSEfirewall2_setup после $network. Не буду обсуждать, что эти скрипты делают конкретно, меня ни один из них не устраивает, но, главное, здесь продемонстрирована необходимость нулевой фазы настройки сетевого экрана, которая переводит сервер в защищенное состояние. А вот схема, используемая в Fedora Core и RHEL, совершенно неприемлема. Кстати, как и всякое использование iptables-save/restore.

Дело в том, что, как уже выше написано, вовсе не обязательно сетевые интерфейсы стартуют нужным образом. Поэтому не факт, что iptables-restore создаст те правила, которые требуются, из-за изменившейся схемы наименования интерфейсов. В схеме SuSE есть скрипт, который теоретически может проанализировать реальное состояние сети и адаптировать сетевой экран нужным образом. Минус только в том, что сетевой экран должен подниматься не отдельным скриптом по расписанию SysVinit, а синхронно с интерфейсом, на который он настраивается! Увы, хотя разработчики Red Hat, Inc. далеки от этой простой мысли, но и в SuSE не лучше. Не может система безопасности стартовать, во первых, после поднятия сетевых интерфейсов (и ведь никто не нормирует данное после), 3 Modern Linux - network virtualizing и, во-вторых, вне всякой связи с настройкой динамических сетевых интерфейсов (wifi, ppp и прочие ADSL).

Возникновение базовой идеи.

Таким образом, причины для определенного рода озабоченности несовершенством сетевых настроек перечислены. Но путей решения указанных проблем множество. Например, можно проследить, как развивались (если не сказать - метались!) предложения разработчиков SUSE по настройке персистентных сетевых имен от версии дистрибутивов 9.х, где эта проблема возникла, до используемых сейчас 10.х. Аналогично и в отношении применяемого в упомянутом дистрибутиве сетевого экрана. Ведь не спроста в его названии использован индекс 2. Можно, например, пойти вообще радикальным путем, как это предлагается в ALT Linux, и использовать иную схему запуска сети [2]. Так что практика размножения сущностей и версий может продолжаться бесконечно. Для меня выбор способа, который, как кажется сейчас, может решить все проблемы разом, произошел почти историческим путем.

Несколько лет назад, как только код сетевого моста [3] был включен в очередной дистрибутив SUSE, так сразу показалось очень интересным использовать сетевой мост в качестве встроенного в сервер коммутатора, подключенного к локальной сети. Во-первых, это позволяло сократить объем дополнительного активного сетевого оборудования, использованного в формировании топологии сети, что было очень выгодным в маленьких офисах или при организации сетевых рабочих групп. И во-вторых, выделяло вакантные интерфейсы для горячей замены в случае отказа оборудования, что очень важно, если сервер обслуживается удаленно, поскольку переключить на запасной интерфейс и быстрей и дешевле, чем дожидаться приезда сисадмина, кроме того, что можно и сам сетевой интерфейс использовать как своего рода файловер. И теперь, по прошествии более 4-х лет со времени внедрения подобного способа разметки локальной сети, можно сказать, что эта технология была испытана многолетней практикой и ни разу не подвела.

Но сейчас появились дополнительные аргументы в пользу использования именно сетевых мостов в качестве основы виртуализации. Логика развития серверных систем неизбежно приводит к необходимости внутренней виртуализации ресурсов и компонентов. Причин этому очень много. Рассмотрение их заслуживает отдельной статьи. Как один из последних опубликованных аргументов приведу мнение Эндрю С. Таненбаума (Andrew S. Tanenbaum) о необходимости изоляции подсистем для увеличения надежности и безопасности [4].

Лучшим способом добиться изоляции является помещение нужных подсистем в отдельную виртуальную машину. К слову сказать, статья по ссылке [4] весьма спорная, о чем свидетельствует и сопутствовавшая ей сетевая дискуссия. Здесь предлагается принять на веру, что рано или поздно, но использование вложенных виртуальных машин внутри серверов станет нормой. Практически во всех видах подобной виртуализации ресурсов внутренний, или зависимый, уровень получает непосредственный доступ к сети путем присоединения к виртуальному сетевому мосту (bridge) [5,6], если исключить всякого рода роутинг. Поэтому будем считать абсолютно обоснованным создание сетевого окружения, приспособленного для подключения виртуальных систем, заранее, в расчете на развитие.

Технология изнутри.

4 Modern Linux - network virtualizing Итак, выбор сделан - сетевой мост. Статей, описывающих настройку сетевых мостов в Linux и сопутствующие этому вопросы огромное число, например [7]. Не будем дублировать очевидное. Обратим внимание лишь на самое важное в контексте предлагаемой идеи. Сам сетевой мост является полностью виртуальным устройством.

Реальный трафик принимается только физическими сетевыми устройствами. Чтобы трафик попал на сетевой мост с некоторого физического устройства или, напротив, с сетевого моста поступил в реальный интерфейс, нужное сетевое устройство должно быть подключено к мосту командой brctl addif . Иначе трафик не будет проходить. Здесь внимательный читатель уже должен все понять - таким путем реализуется внутренняя коммутация. Это основная идея. То есть, изначально сетевой мост предназначен для объединения нескольких реальных сетевых интерфейсов в общий коммутатор. Но ничего не мешает использовать выделенные сетевые мосты для каждого реального интерфейса. Собственно, как и наоборот - для каждого (внимание: здесь еще одно усложнение) реального, но виртуализованного, путем назначения на выделенный специальный сетевой мост, использовать один или несколько аппаратных сетевых интерфейсов из массива имеющихся в составе оборудования сервера. И вот эту привязку можно производить динамически. Все сказанное иллюстрируется схемой на рисунке 1.

Рисунок 1. Сравнение традиционного способа настройки с виртуализованным интерфейсом.

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

5 Modern Linux - network virtualizing Если сетевая карта вышла из строя, то подключается предназначенная на замену. Если в джек сетевой карты вставлен плуг другого кабеля, то она подключается на правильный виртуальный интерфейс, согласно произведенной кабельной коммутации, после проверки трафика на данном кабельном подключении. Если нужно отключить сервер временно от некоторой сети, то можно не вынимать кабель из сетевой карты, не останавливать сетевые сервисы, не запирать файрвол, а просто отсоединить физический интерфейс от используемого моста. Но на этом преимущества не кончаются. Все почти также как и с вытянутым носом киплинговского слоненка.

Физика работы сетевого моста требует, чтобы используемое аппаратное устройство принимало из сети пакеты для адреса сетевого моста, в который это устройство включено.

Такое возможно, если в сетевой карте отключить аппаратную фильтрацию пакетов и перевести ее в promiscuous-режим, или, как будем называть это далее, перевести в режим прослушивания. Самый простой способ добиться этого - поднять интерфейс с адресом 0.0.0.0 или, что более верно, вовсе без адреса. Собственно, в ином состоянии утилита brctl откажется подключать интерфейс к мосту. И в процессе подключения интерфейс будет переведен в режим прослушивания автоматически. Но в этом тезисе ничего не сказано про наличие действительного адреса у самого сетевого моста. Он может иметь реальный адрес, может иметь несколько адресов как алиасы (синонимы), может иметь адрес немарштуризируемый в используемой сети, или вовсе не иметь адреса. Ну и, наконец, сетевой мост может вообще не соединяться с физическим интерфейсом. Тогда он образует полностью виртуальный коммутатор внутренней сети, к которому могут подключаться виртуальные машины через виртуальные же интерфейсы, и использовать его как внутреннюю сеть кластера. Рассмотрим эти варианты подробнее и проверим экспериментально.

Сетевой мост с реальным адресом.

Эту часть экспериментов будем проводить в системе, установленной внутрь виртуальной машины с полной и достаточно тщательной эмуляцией, а именно внутрь VMware. Но, уверяю Вас, все будет полностью работоспособно и на реальном оборудовании. Более того, такие условия позволят сделать некоторые дополнительные выводы.

Виртуальный интерфейс с реальным адресом подходит для использования в самом распространенном и одновременно тривиальном случае. Это, фактически, эквивалентная замена ортодоксального интерфейса на пару, состоящую из виртуального и реального устройства. К мосту с актуальным адресом подключается безадресный физический интерфейс, который принимает все пакеты в данной сети, а фильтрацию производит IP стек, работающий поверх сетевого моста. То есть сетевой экран тоже настраивается на сетевом мосту. И все используемые сетевые сервисы также слушают адрес сетевого моста.

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

# ifdown eth eth0 device: Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE] (rev 10) eth0 configuration: eth-id-00:0c:29:89:80:c # ip link sh 6 Modern Linux - network virtualizing 1: lo: mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00: 2: eth0: mtu 1500 qdisc pfifo_fast qlen link/ether 00:0c:29:89:80:c2 brd ff:ff:ff:ff:ff:ff 3: sit0: mtu 1480 qdisc noop link/sit 0.0.0.0 brd 0.0.0. Далее переименуем его, так как реальное имя нам понадобится далее для создаваемого виртуального интерфейса:

# ip link set dev eth0 name hweth # ip link sh 1: lo: mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00: 2: hweth0: mtu 1500 qdisc pfifo_fast qlen link/ether 00:0c:29:89:80:c2 brd ff:ff:ff:ff:ff:ff 3: sit0: mtu 1480 qdisc noop link/sit 0.0.0.0 brd 0.0.0. Теперь переименованный интерфейс снова можно включить. Впредь он будет играть роль простого элемента коммутации без собственного IP адреса:

# ip link set dev hweth0 up # ifconfig hweth hweth0 Link encap:Ethernet HWaddr 00:0C:29:89:80:C inet6 addr: fe80::20c:29ff:fe89:80c2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric: RX packets:15 errors:0 dropped:0 overruns:0 frame: TX packets:31 errors:0 dropped:0 overruns:0 carrier: collisions:0 txqueuelen: RX bytes:2629 (2.5 Kb) TX bytes:3211 (3.1 Kb) Interrupt:177 Base address:0x Создадим сетевой мост с предпочтительным именем, в нашем случае это eth0, так как виртуализацию этого устройства мы и производим:

# brctl addbr eth # brctl show bridge name bridge id STP enabled interfaces eth0 8000.000000000000 no # ip link set dev eth0 up # ip link sh 1: lo: mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00: 2: hweth0: mtu 1500 qdisc pfifo_fast qlen link/ether 00:0c:29:89:80:c2 brd ff:ff:ff:ff:ff:ff 3: sit0: mtu 1480 qdisc noop link/sit 0.0.0.0 brd 0.0.0. 4: eth0: mtu 1500 qdisc noqueue link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff В приведенном выше протоколе предлагаю обратить внимание на то, что вирутальный интерфейс eth0 даже после включения командой ip link set up не имеет канального адреса (MAC). Даже присвоение ему IP адреса ничего не меняет:

# ip addr add 192.168.0.111/32 dev eth # ifconfig eth eth0 Link encap:Ethernet HWaddr 00:00:00:00:00: inet addr:192.168.0.111 Bcast:0.0.0.0 Mask:255.255.255. 7 Modern Linux - network virtualizing inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric: RX packets:0 errors:0 dropped:0 overruns:0 frame: TX packets:17 errors:0 dropped:0 overruns:0 carrier: collisions:0 txqueuelen: RX bytes:0 (0.0 b) TX bytes:1536 (1.5 Kb) И это объяснимо, так как виртуальный интерфейс пока не скоммутирован ни с одним реальным физическим интерфейсом, то есть, не подключен ни к одной сети. Проверим это:

# ip route add 192.168.0.0/24 dev eth # ping -c 1 192.168.0. PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.

From 192.168.0.111: icmp_seq=1 Destination Host Unreachable --- 192.168.0.1 ping statistics -- 1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 1ms Как видите, траффик не идет. Точно такая же картина и при попытке достучаться до адреса 192.168.0.111 с других хостов сети. Теперь соединим eth0 с физическим интерфейсом:

# brctl show bridge name bridge id STP enabled interfaces eth0 8000.000000000000 no # brctl addif eth0 hweth < здесь происходит автоматический перевод hweth0 в режим прослушивания > # ip link sh 1: lo: mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00: 2: hweth0: mtu 1500 qdisc pfifo_fast qlen link/ether 00:0c:29:89:80:c2 brd ff:ff:ff:ff:ff:ff 3: sit0: mtu 1480 qdisc noop link/sit 0.0.0.0 brd 0.0.0. 4: eth0: mtu 1500 qdisc noqueue link/ether 00:0c:29:89:80:c2 brd ff:ff:ff:ff:ff:ff # brctl show bridge name bridge id STP enabled interfaces eth0 8000.000c298980c2 no hweth # ping -c 1 192.168.0. PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.

64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=29.9 ms --- 192.168.0.1 ping statistics -- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 29.959/29.959/29.959/0.000 ms Разберем, описанное в протоколе. Во-первых, в точке, выделенной ремаркой, произошел автоматический перевод физического интерфейса в режим прослушивания. Эмулятор это поймал и выдал запрос оператору (см. рисунок 2).

8 Modern Linux - network virtualizing Рисунок 2. Запрос на перевод интерфейса в режим прослушивания.

Затем, не смотря на предупреждение о невозможности данной операции, тем не менее, все работает, как следовало. Из чего можно сделать вывод, что реальный интерфейс компьютера, в котором запущен эмулятор VMware, и так уже работает в состоянии promiscuous (кстати, это не отображается системными флагами), что подтверждает тезис о неизбежности перехода к виртуализованным сетевым интерфейсам в перспективе. В третьих, сетевой мост получает канальный адрес, такой же как адрес первого присоединенного интерфейса. Ну и, наконец, траффик - пошел! Обратите внимание на задержки. Они велики. Но это лишь следствие инерционности работы сетевого моста. И немного спустя все приходит в норму. Например, так выглядит пингование с удаленного хоста спустя некоторое время:

server:~ # ping -c 1 192.168.0. PING 192.168.0.111 (192.168.0.111) 56(84) bytes of data.

64 bytes from 192.168.0.111: icmp_seq=1 ttl=64 time=0.498 ms --- 192.168.0.111 ping statistics -- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.498/0.498/0.498/0.000 ms То есть на рабочей производительности это не сказывается. Более того, подобное подключение полностью прозрачно для всех сетевых служб даже канального уровня.

Например, переключим виртуальный интерфейс в режим DHCP:

9 Modern Linux - network virtualizing # ip addr del 192.168.0.111/32 dev eth # ifconfig eth eth0 Link encap:Ethernet HWaddr 00:0C:29:89:80:C inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric: RX packets:8 errors:0 dropped:0 overruns:0 frame: TX packets:41 errors:0 dropped:0 overruns:0 carrier: collisions:0 txqueuelen: RX bytes:860 (860.0 b) TX bytes:3502 (3.4 Kb) # dhclient eth Internet Systems Consortium DHCP Client V3.0. Copyright 2004-2005 Internet Systems Consortium.

All rights reserved.

For info, please visit Listening on LPF/eth0/00:0c:29:89:80:c Sending on LPF/eth0/00:0c:29:89:80:c Sending on Socket/fallback DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval DHCPOFFER from 192.168.0. DHCPREQUEST on eth0 to 255.255.255.255 port DHCPACK from 192.168.0. bound to 192.168.0.178 -- renewal in 1429 seconds.

# ifconfig eth eth0 Link encap:Ethernet HWaddr 00:0C:29:89:80:C inet addr:192.168.0.178 Bcast:192.168.0.255 Mask:255.255.255. inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric: RX packets:25 errors:0 dropped:0 overruns:0 frame: TX packets:56 errors:0 dropped:0 overruns:0 carrier: collisions:0 txqueuelen: RX bytes:2651 (2.5 Kb) TX bytes:5370 (5.2 Kb) Как видите, все работает. Собственно, другого и не стоило бы ожидать, поскольку уже было сказано, что на подобной технологии давно и устойчиво работают такие способы виртуализации серверов как UML, XEN, и даже VMware.

Безадресный мост, мост с немаршрутизируемом адресом и внутренний мост сервера.

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

Но ведь самое главное преимущества сетевого моста в том, что он позволяет работать с включенными в него интерфейсами на уровне L2 модели ISO OSI. Поэтому наиболее уместным кандидатом на такую интеграцию можно считать виртуальный интерфейс гостевого сервера. Итак, рассмотрим, как можно манипулировать сетевыми подключениями вложенного сервера UML (user mode linux), подключенного к специально созданным сетевым мостам. Этот пример, к сожалению, не доступен на openSUSE Linux 10.1 из-за прекращения поддержки UML в указанной версии. Утилиты для настройки специальных виртуальных устройств tun/tap можно найти только в версии 10.0 этого дистрибутива. И хотя альтернативный вариант виртуализации Xen, который работает с сетью точно также, присутствует и там и там, мы будем демонстрировать все приемы на UML поскольку эта технология более прозрачна для анализа.

10 Modern Linux - network virtualizing Предположим, что все необходимые элементы для запуска виртуальной ОС уже созданы.

Подробно данная тема затронута в следующих статьях цикла. Здесь же прошу поверить на слово. Структура тестовой системы изображена на рисунке 3.

Рисунок 3. Тестовая система с виртуальными интерфейсами и сетями.

Внутри хостовой, той которая служит основой, машины создан ряд сетевых мостов по схеме описанной выше:

server:~ # brctl show bridge name bridge id STP enabled interfaces eth0 8000.000479661b70 no hweth hweth eth1 8000.000000000000 no В мосту eth0 два реальных порта, а в мосту eth1 вообще нет физических интерфейсов и он поэтому полностью виртуальный. Но даже в том виде как он существует, без канального адреса, он вполне работоспособен:

server:~ # ifconfig eth eth1 Link encap:Ethernet HWaddr 00:00:00:00:00: inet addr:192.168.254.1 Bcast:192.168.254.255 Mask:255.255.255. inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric: RX packets:0 errors:0 dropped:0 overruns:0 frame: TX packets:28 errors:0 dropped:0 overruns:0 carrier: 11 Modern Linux - network virtualizing collisions:0 txqueuelen: RX bytes:0 (0.0 b) TX bytes:2166 (2.1 Kb) И через него легко идет реальный трафик:

server:~ # ping -c 1 192.168.254. PING 192.168.254.1 (192.168.254.1) 56(84) bytes of data.

64 bytes from 192.168.254.1: icmp_seq=1 ttl=64 time=0.049 ms --- 192.168.254.1 ping statistics -- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.049/0.049/0.049/0.000 ms После запуска виртуальной машины в системе создаются два псевдоустройства tap0 и tap1.

Эти устройства передают трафик, который на них маршрутизируется обработчику из пользовательского пространства, в данном случае виртуальной машине UML. Их создание производится командой tunctl непосредственно перед запуском UML, которому названия полученных устройств передаются в командной строке. И ОС, запущенная внутри виртуальной машины (в случае UML, сама модифицированная ОС и является такой виртуальной машиной) использует эти псевдоустройства в качестве эмулятора аппаратных сетевых интерфейсов. На стороне хостовой машины устройства tun/tap подключаются внутрь сетевых мостов, если предполагается разрешить на них работу на уровне L2. Мы так и поступим:

server:~ # brctl show bridge name bridge id STP enabled interfaces eth0 8000.000479661b70 no hweth hweth tap eth1 8000.2e48adefd363 no tap Сразу после подключения к мосту eth1 первого, как ему представляется реального устройства, мост получает и собственный канальный адрес:

server:~ # ifconfig eth eth1 Link encap:Ethernet HWaddr 2E:48:AD:EF:D3: inet addr:192.168.254.1 Bcast:192.168.254.255 Mask:255.255.255. inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric: RX packets:7 errors:0 dropped:0 overruns:0 frame: TX packets:44 errors:0 dropped:0 overruns:0 carrier: collisions:0 txqueuelen: RX bytes:372 (372.0 b) TX bytes:3628 (3.5 Kb) server:~ # ifconfig tap tap0 Link encap:Ethernet HWaddr 2E:48:AD:EF:D3: inet6 addr: fe80::2c48:adff:feef:d363/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric: RX packets:8 errors:0 dropped:0 overruns:0 frame: TX packets:6 errors:0 dropped:13 overruns:0 carrier: collisions:0 txqueuelen: RX bytes:560 (560.0 b) TX bytes:548 (548.0 b) Этот адрес случайным образом был установлен для tap0 при его создании. В процессе дальнейшей работы данный MAC более нигде не будет фигурировать, так как устройство tun/tap представляет собой туннель, в котором реальным является лишь пользовательский 12 Modern Linux - network virtualizing конец, находящийся внутри виртуальной машины UML. И если внутри UML поднять интерфейс eth0, который будет привязан к виртуальному устройству tap0, с некоторым адресом, то внутри виртуальной сети появится новый хост с указанным адресом:

server:~ # ping -c 1 192.168.254. PING 192.168.254.2 (192.168.254.2) 56(84) bytes of data.

64 bytes from 192.168.254.2: icmp_seq=1 ttl=64 time=0.125 ms --- 192.168.254.2 ping statistics -- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.125/0.125/0.125/0.000 ms server:~ # arp -n Address HWtype HWaddress Flags Mask Iface 192.168.254.2 ether FE:FD:C0:A8:01:00 C eth Все это в точности совпадает с настройками интерфейса eth0 в UML:

uml:~ # ifconfig eth eth0 Link encap:Ethernet HWaddr FE:FD:C0:A8:01: inet addr:192.168.254.2 Bcast:192.168.254.255 Mask:255.255.255. inet6 addr: fe80::fcfd:c0ff:fea8:100/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric: RX packets:103 errors:0 dropped:0 overruns:0 frame: TX packets:7 errors:0 dropped:0 overruns:0 carrier: collisions:0 txqueuelen: RX bytes:18261 (17.8 Kb) TX bytes:518 (518.0 b) Interrupt: Таким образом, продемонстрирована работоспособность полностью виртуальной сети. В данном случае необходимость такой сети вызвана тем, что нужно было создать средство лобщения запускаемых виртуальных машин с хостовым сервером. Например, им всем через внутреннюю сеть раздается рабочий дистрибутив:

server:~ # showmount -e Export list for server:

/srv/susedvd/SU1000_001 192.168.254.0/255.255.255.0,localhost Эта связь может стать особенно важной, если сам сервер не будет иметь иного способа подключиться к гостевой машине. Спросите, как это может быть? Очень просто! Для этого рассмотрим второй виртуальный интерфейс на рисунке 3, который подключает и сервер и его гостевую ОС к локальной сети. Для этого используется мост eth0:

server:~ # brctl show bridge name bridge id STP enabled interfaces eth0 8000.000479661b70 no hweth hweth tap eth1 8000.2e48adefd363 no tap Псевдоустройство tap1 точно также как и tap0 безадресное, а вот сам мост имеет адрес:

server:~ # ifconfuigeth eth0 Link encap:Ethernet HWaddr 00:04:79:66:1B: inet addr:192.168.0.9 Bcast:192.168.0.255 Mask:255.255.255. inet6 addr: fe80::200:ff:fe00:0/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric: RX packets:14968 errors:0 dropped:0 overruns:0 frame: TX packets:499 errors:0 dropped:0 overruns:0 carrier: collisions:0 txqueuelen: 13 Modern Linux - network virtualizing RX bytes:792910 (774.3 Kb) TX bytes:77724 (75.9 Kb) Внутри UML интерфейс, соответствующий tap1, настроен для работы в локальной сети:

uml:~ # ifconfig eth eth1 Link encap:Ethernet HWaddr FE:FD:C0:A8:01: inet addr:192.168.0.2 Bcast:192.168.0.255 Mask:255.255.255. inet6 addr: fe80::fcfd:c0ff:fea8:101/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric: RX packets:92240 errors:0 dropped:0 overruns:0 frame: TX packets:314 errors:0 dropped:0 overruns:0 carrier: collisions:0 txqueuelen: RX bytes:4576001 (4.3 Mb) TX bytes:13468 (13.1 Kb) Interrupt: При попытке пропинговать адрес UML получаем ответы:

server:~ # ping -c 1 192.168.0. PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.

64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=7.14 ms --- 192.168.0.2 ping statistics -- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 7.142/7.142/7.142/0.000 ms server:~ # arp -n Address HWtype HWaddress Flags Mask Iface 192.168.0.2 ether FE:FD:C0:A8:01:01 C eth 192.168.254.2 ether FE:FD:C0:A8:01:00 C eth Может это вызвано неким локальным феноменом? Проверим видимость адреса UML с еще двух компьютеров в сети. После отправки ICMP запросов внутри arp-хеша появились новые записи:

server:~ # arp -n Address HWtype HWaddress Flags Mask Iface 192.168.0.2 ether FE:FD:C0:A8:01:01 C eth 192.168.0.10 ether 00:05:5D:E7:86:39 C eth 192.168.0.11 ether 00:05:5D:74:DD:5D C eth Значит, все произошло успешно. Теперь сбросим адрес у самого сетевого моста. Это приведет к невозможности работы с локальной сетью внутренних процессов сервера. На рисунке 3 красная пунктирная линия обозначает прерванные связи.

server:~ # ip addr sh dev eth 7: eth0: mtu 1500 qdisc noqueue link/ether 00:04:79:66:1b:70 brd ff:ff:ff:ff:ff:ff inet 192.168.0.9/24 brd 192.168.0.255 scope global eth inet6 fe80::200:ff:fe00:0/64 scope link valid_lft forever preferred_lft forever server:~ # ip addr del 192.168.0.9/24 dev eth server:~ # ip route sh 10.0.0.0/24 dev eth2 proto kernel scope link src 10.0.0. 192.168.254.0/24 dev eth1 proto kernel scope link src 192.168.254. 127.0.0.0/8 dev lo scope link Все! Теперь тот самый случай - никакая сеть кроме виртуальной хостовому серверу не доступна:

server:~ # ping -c 1 192.168.0. connect: Network is unreachable 14 Modern Linux - network virtualizing А вот с других хостов пинги проходят вполне успешно. Адрес внутреннего виртуального UML сервера присутствует в локальной сети и нормально работает. Если к данному мосту подключить следующую виртуальную систему с помощью соответствующего tun/tap устройства, на пользовательской стороне которого поднят иной адрес, то и он станет виден со стороны сети, подключенной к физическому интерфейсу сетевого моста. И так далее.

Получился безадресный сетевой мост, который работает как arp-прокси и транслирует трафик с подключенных виртуальных хостов. В чем его ценность. Такая схема позволяет защитить хостовую ОС от враждебного трафика сети, если вместо приватной сети используется, например, Интернет. Чисто рациональная польза, когда безадресный хостер используется как платформа для запуска виртуальных гостевых ОС, каждой со своим собственным адресом. Ну и, наконец, ничего не мешает применять на таком несущем сетевом мосте собственную сетевую разметку, не маршрутизируемую общим порядком, создавая скрытую служебную сеть. Есть, правда, и тут некоторые подводные камни.

Дело в том, что процедура взаимодействия сетевых узлов на уровне L2 является слабо защищенной. И в некоторых сетях используются самодельные службы и другие нестандартные настройки, контролирующие канальное взаимодействие. И хотя, описанный выше прием с безадресным мостом прекрасно работает (не говоря уже, что такой классический способ настройки моста описан в документации), но бывали случаи, когда такая настройка действовала как DoS атака L2. Точно также стоит очень внимательно отнестись к множеству физических интерфейсов объединенных в мост - их неверное подключение может создать неконтролируемые пути доступа или утечки трафика и тоже стать источником L2 проблем.

Заключение.

Итак, подмена сетевых устройств виртуальными сетевыми мостами создает массу возможностей для манипуляции. В случае использования виртуальных серверов вообще такая настройка является единственно возможной. Но нельзя же каждый раз выполнять приведенные в статье команды, даже если их записать в отдельный скрипт. О том, как встроить предлагаемую схему разметки сетевых устройств в структуру реальных стартовых скриптов без каких-нибудь конфликтов для работы остальных подсистем, поговорим во второй части статьи.

Использованные ссылки:

1. Сайт проект Open SUSE и область загрузки дистрибутива openSUSE 10. 2. Проект альтернативных сетевых скриптов.

3. Страница wiki, на которую переадресует бывший домашний сайт проекта IEEE 802.1d ethernet bridging 4. Andrew S. Tanenbaum, Jorrit N. Herden, and Herbert Bos, Vrije Universiteit, Amsterdam, May 2006, Can We Make Operating System Reliable and Secure? 15 Modern Linux - network virtualizing ndex.jsp?&pName=computer_level1_article& 5. User Mode Linux. Set up the network.

6. openSUSE. Xen and Virtual Network.

7. Павел Закляков. Разводной мост на Linux (bridging firewalls). Системный администратор, №4, 2003 год.

   Книги, научные публикации