Статья опубликована в журнале «Системный Администратор»
Освоим построение и конфигурирование виртуальных компьютерных сетей любых масштабов в рамках одной виртуальной машины.
Что это и для чего
Работая над статьей, посвященной Open vSwitch, проходя по различным ссылкам в поисках хоть какой-нибудь полезной информации, открыл для себя проект под названием mininet [1]. Будучи активным читателем технической и компьютерной литературы, журналов и новостей, думал, что все самое интересное я уже изучил и попробовал. Но, этот проект меня искренне удивил. Я не уверен в практической ценности данного решения для большинства читателей, но мой личный интерес к нему подтолкнул к написанию статьи.
Mininet — это эмулятор компьютерной сети. Под компьютерной сетью подразумеваются простые компьютеры — хосты, коммутаторы, а так же OpenFlow-контроллеры. С помощью простейшего синтаксиса в примитивном интерпретаторе команд можно разворачивать сети из произвольного количества хостов, коммутаторов в различных топологиях и все это в рамках одной виртуальной машины(ВМ). На всех хостах можно изменять сетевую конфигурацию, пользоваться стандартными утилитами(ipconfig, ping) и даже получать доступ к терминалу. На коммутаторы можно добавлять различные правила и маршрутизировать трафик. В общем, получается довольно интересная вещь, позволяющая познакомиться с устройством и функционированием компьютерных сетей без необходимости использования какого либо сетевого оборудования.
Как это работает
Начиная с версии 2.6.24, ядром Linux поддерживаются механизмы виртуализации и изоляции – Cgroups[2], которые позволяют обеспечить сетевыми интерфейсами, таблицами маршрутизации и ARP-таблиами процессы в рамках одной операционной системы. Это один из видов виртуализации на уровне ОС, позволяющий запустить множество однотипных процессов в изолированном и ограниченном по ресурсам окружении. Подобные техники позволяют Mininet создавать в пространстве ядра или пользователя коммутаторы, OpenFlow-контроллеры и хосты, и взаимодействовать в рамках моделируемой сети. В качестве виртуальных коммутаторов используется адаптированная реализация Open vSwitch’a.
Основная функциональность Mininet реализована на Python, за исключением некоторых утилит написанных на Си. Практически любая произвольная топология может быть описана с помощью специального синтаксиса на Python. В интернете можно найти множество интересных лабораторных работ на базе mininet, решающих различные задачи. Например реализация простого маршрутизатора[3].
Как этим пользоваться
Вся работа с виртуальной сетью mininet, а именно развертывание сети желаемой топологии, изменение различных параметров хостов или коммутаторов и т. п., производится в простом интерпретаторе команд – mn.
$ sudo mn
Запущенный без параметров, mn перейдет в режим интерпретации команд. При этом по умолчанию будет создана минимальная сеть, состоящая из двух хостов (h1, h2), коммутатора (s1) и OpenFlow-контроллера (c1).
$ sudo mn
*** Creating network
*** Adding controller
*** Adding hosts:
h1 h2
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1)
*** Configuring hosts
h1 h2
*** Starting controller
*** Starting 1 switches
s1
*** Starting CLI:
mininet>
Интерпретатор mininet использует ряд собственных команд, позволяющих управлять виртуальной сетью практически как настоящей. Ниже приведены примеры основных возможностей.
Вывести список всех хостов, коммутаторов и контроллеров можно с помощью команды nodes
mininet> nodes
available nodes are:
h1 h2 c0 s1
посмотреть топологию сети, а именно сопоставление портов коммутатора и хостов можно с помощью команды net:
mininet> net
c0
s1 lo: s1-eth1:h1-eth0 s1-eth2:h2-eth0
h1 h1-eth0:s1-eth1
h2 h2-eth0:s1-eth2
вывести конфигурацию сетевого интерфейса конкретного хоста можно с помощью классической команды ifconfig перед которой необходимо указать имя конкретного узла:
mininet> h1 ifconfig
h1-eth0 Link encap:Ethernet HWaddr 96:0d:f2:1a:e3:91
inet addr:10.0.0.1 Bcast:10.255.255.255 Mask:255.0.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:11 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:846 (846.0 B) TX bytes:468 (468.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
В приведенной выше команде, вместо имени хоста можно указать конкретный коммутатор, тогда будет выведена конфигурация его портов.
Любой из портов коммутатора можно выключить и включить по желанию:
mininet> link s1 h1 down
mininet> link s1 h1 up
Посмотреть таблицу маршрутизации конкретного хост можно аналогично с использованием привычной команды route:
mininet> h1 route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
10.0.0.0 * 255.0.0.0 U 0 0 0 h1-eth0
Ну и конечно же выполнить пинг, как же без него:
mininet> h1 ping h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=4.11 ms
64 bytes from 10.0.0.2: icmp_req=2 ttl=64 time=0.252 ms
^C
— 10.0.0.2 ping statistics —
2 packets transmitted, 2 received, 0% packet loss, time 4999ms
rtt min/avg/max/mdev = 0.066/0.779/4.119/1.495 ms
пинг каждого с каждым:
mininet> pingall
*** Ping: testing ping reachability
h1 -> h2
h2 -> h1
*** Results: 0% dropped (0/2 lost)
В принципе, на каждом из хостов, указывая предварительно его имя, можно выполнять большинство стандартных команд linux. Например посмотреть процессы любого из хостов или коммутаторов поможет все тот же ps:
mininet> s1 ps
PID TTY TIME CMD
1 ? 00:00:00 init
2 ? 00:00:00 kthreadd
3 ? 00:00:00 ksoftirqd/0
…
(вывод сокращен)
при этом любой из процессов можно завершить с помощью стандартного kill -9.
Кроме проверки доступности узлов с помощью ping можно еще протестировать пропускную способность между узлами с помощью старого доброго iperf:
mininet> iperf h1 h2
Фото masterimvmeste.ru.
*** Iperf: testing TCP bandwidth between h1 and h2
waiting for iperf to start up…*** Results: [‘1.35 Gbits/sec’, ‘1.36 Gbits/sec’]
Забегая немного вперед, скажу, что пропускная способность интерфейсов может быть ограниченна от 10 до 1000 Mbit/s. Но об этом немного ниже.
Ну и в конце концов, можно просто получить терминал к любому из узлов:
mininet> xterm h1
Дополнительные сервисы
На каждом из виртуальных хостов, помимо стандартных процессов есть возможность запускать сторонние сервисы. Например это может быть простой веб-сервер на Python:
mininet> h1 python -m SimpleHTTPServer 80 &
и попробовать подключиться к нему с другого узла:
mininet> h2 wget -O — h1
—2013-11-06 03:44:17— http://10.0.0.1/
Connecting to 10.0.0.1:80… connected.
HTTP request sent, awaiting response… 200 OK
Length: 248 [text/html]
Saving to: `STDOUT’
<!DOCTYPE html PUBLIC «-//W3C//DTD HTML 3.2 Final//EN»><html>
<title>Directory listing for /</title>
…
(вывод сокращен)
можно завершить работу веб-сервера, если необходимо:
mininet> h1 kill %python
Виртуальная сеть mininet не существует постоянно — она создается при вызове mn с какими-то конкретными параметрами или без таковых и уничтожается при выходе из интерпретатора. Все это происходит почти мгновенно. Даже крупная сеть с несколькими сотнями хостов и десятками коммутаторов создается в считанные секунды. И все это на однопроцессорной виртуальной машине с одним гигабайтом оперативной памяти.
Корректно свернуть всю виртуальную сеть и выйти в оболочку ОС можно командой quit.
В случае если работа интерпретатора была завершена некорректно, избавиться от повисших процессов и прочих служебных данных можно командой
$ sudo mn -c
Усложним топологию
Как и в реальном, физическом мире, построение сети в эмуляторе Mininet начинается с топологии. Топология определяет сколько будет хостов, коммутаторов а так же каким образом они будут объедены в сеть.
Существует четыре базовых топологи, которые можно использовать, «не заморачиваясь» с синтаксисом Python — они уже описаны и реализованы в виде параметров mn. Ниже приведены подробности про каждую из них.
mininal. Используется по умолчанию при запуске mn без параметров. В этом случае создаются два хоста, подключенные к одному коммутатору, который, в свою очередь управляется OpenFlow-контроллером. В данной топологии нельзя задать произвольное число хостов или коммутаторов.
single. Как и в случае с minimal, все хосты подключаются к одному коммутатору. Единственное отличие — это возможность указать их количество.
$ sudo mn —topo single,24
*** Creating network
*** Adding controller
*** Adding hosts:
h1 h2 h3 h4 h5 h6 h7 h8 h9 h10 h11 h12 h13 h14 h15 h16 h17 h18 h19 h20 h21 h22 h23 h24
*** Adding switches:
s1
*** Adding links:
(h1, s1) (h2, s1) (h3, s1) (h4, s1) (h5, s1) (h6, s1) (h7, s1) (h8, s1) (h9, s1) (h10, s1) (h11, s1) (h12, s1) (h13, s1) (h14, s1) (h15, s1) (h16, s1) (h17, s1) (h18, s1) (h19, s1) (h20, s1) (h21, s1) (h22, s1) (h23, s1) (h24, s1)
*** Configuring hosts
h1 h2 h3 h4 h5 h6 h7 h8 h9 h10 h11 h12 h13 h14 h15 h16 h17 h18 h19 h20 h21 h22 h23 h24
*** Starting controller
*** Starting 1 switches
s1
*** Starting CLI:
mininet>
linear. Топология описывает сеть в которой все хосты подключены к собственным коммутаторам, которые в свою очередь соединены между собой.
$ sudo mn —topo linear,6
*** Creating network
*** Adding controller
*** Adding hosts:
h1 h2 h3 h4 h5 h6
*** Adding switches:
s1 s2 s3 s4 s5 s6
*** Adding links:
(h1, s1) (h2, s2) (h3, s3) (h4, s4) (h5, s5) (h6, s6) (s1, s2) (s2, s3) (s3, s4) (s4, s5) (s5, s6)
*** Configuring hosts
h1 h2 h3 h4 h5 h6
*** Starting controller
*** Starting 6 switches
s1 s2 s3 s4 s5 s6
*** Starting CLI:
mininet>
tree. Древовидная топология, наиболее сложная из перечисленных. Здесь в качестве параметров можно указать глубину иерархии коммутаторов (depth) а так же число подключенных к ним хостов (fanout).
$ sudo mn —topo tree,depth=3,fanout=4
Команда, представленная выше построит сеть с классической трехуровневой моделью. Когда к каждому коммутатору уровня доступа(access) будут подключены по четыре хоста. Коммутаторы доступа в свою очередь будут включены в распределение(distribution) из четырех коммутаторов которые в свою очередь заводятся в единое ядро(core). К сожалению, такие возможности как стекирование коммутаторов или агрегация каналов а так же стандартные VLAN’ы не реализованы в mininet, что делает данную модель не совсем реалистичной. Но в общих чертах она довольно схожа.
В случае если есть базовые познания Python и необходима особенная топология, ее можно описать самостоятельно, аналогично примеру указанному в ссылках[4].
Построить сеть используя собственную топологию, можно с помощью ключа —custom:
$ sudo mn —custom /<путь к скрипту>/topo-2sw-2host.py —topo mytopo
Параметры сети
По умолчанию, все объекты сети mininet соединяются виртуальными гигабитными каналами.
В этом можно убедиться выполнив команду iperf в интерпретаторе mininet, которая проведет тестирование пропускной способности между двумя объектами сети.
mininet> iperf
*** Iperf: testing TCP bandwidth between h1 and h2
waiting for iperf to start up…*** Results: [‘1.26 Gbits/sec’, ‘1.28 Gbits/sec’]
mininet>
Правда, не совсем понятно, почему тест показывает немного завышенные результаты. Думаю это как то связанно с особенностями виртуальной среды. Возможно, при использовании каналов по умолчанию (1 Gb), ограничения не применяются вовсе.
Следует иметь в виду, что коммутатор, работающий в пользовательском пространстве, а не в пространстве ядра, выполняется значительно медленнее.
$ sudo mn —switch user —test iperf
…
*** Iperf: testing TCP bandwidth between h1 and h2
*** Results: [‘360 Mbits/sec’, ‘360 Mbits/sec’]
…
(вывод сокращен)
При желании, можно ограничить пропускную способность каналов до произвольных значений. А в добавок к этому есть возможность указать задержки в канале(latency).
$ sudo mn —link tc,bw=10,delay=10ms
Команда выше, разворачивает сеть по умолчанию, с пропускной способностью между узлами ограниченной в 10 Mbit/s и минимальными задержками в 10 ms.
Теперь пинг между узлами будет идти с задержкой в 10 ms.
Выводы
Виртуализация, везде и всюду. Начиная от уже классической серверной и заканчивая виртуальными Ethernet-портами в современных блейд-системмах. Виртуализируется все, и mininet — еще один хороший тому пример. Возможно, именно этим проект меня и зацепил. Даже сейчас, познакомившись поближе, честно говоря не вижу в нем какой то практической ценности. Особенно, для уже состоявшегося технического специалиста. Но сама реализация интересна и возможно, это решение сможет послужить для кого то инструментом моделирования а различные эксперименты помогут разобраться в принципах работы вычислительных сетей. В Интеренете доступны различные практические задачи и лабораторные работы построенные на базе mininet. Они широко используются в таких небезызвестных учебных заведениях, как Стэнфорд, Принстон и возможно, будут полезны вам.
Ссылки
[1] Пожалуй единственная информация о mininet на русском — http://www.xakep.ru/post/60886/
[2] Технология Cgroups — http://ru.wikipedia.org/wiki/Cgroups
[3] Реализация маршрутизатора в mininet — https://github.com/mininet/mininet/wiki/Simple-Router
[4] Пример скрипта на Python описывающего произвольную топологию — http://pastebin.com/YS6aguDR
Помогла ли вам статья?