Как стать автором
Обновить

Учебник по симулятору сети ns-3. Глава 6

Время на прочтение 38 мин
Количество просмотров 2.9K
Ненормальное программирование *Анализ и проектирование систем *C++ **nix *Сетевые технологии *
Туториал


главы 1,2
глава 3
глава 4
глава 5


Глава 6 Строим топологии
6.1 Построение топологии шинной сети
6.2 Модели, атрибуты и реальность
6.3 Построение топологии беспроводной сети
6.4 Очереди в ns-3
6.4.1 Модели очередей доступные в ns-3
6.4.2 Изменение настроек по умолчанию


Глава 6


Строим топологии


6.1 Построение топологии шинной сети


В этом разделе мы собираемся расширить наши знания по сетевым устройствам и каналам ns‑3, чтобы охватить пример шинной сети. Ns‑3 предоставляет сетевое устройство и канал, который мы называем CSMA (множественный доступ с контролем несущей).


Устройство CSMA в ns‑3 моделирует простую сеть в духе Ethernet. Настоящий Ethernet использует CSMA/CD (множественный доступ с контролем несущей и обнаружением коллизий) с экспоненциально нарастающей конкуренцией за общую среду передачи. Устройство и канал CSMA ns‑3 моделируют это только отчасти.


Подобно тому, как мы использовали вспомогательные объекты при построении топологий точка-точка, в этом разделе мы увидим аналогичных помощников для топологии CSMA. Внешний вид и работа этих помощников должны выглядеть вам вполне знакомо.


В нашей директории examples/tutorial мы предоставляем пример сценария. Этот скрипт основан на сценарии first.cc и добавляет сеть CSMA к симуляции точка-точка, которую мы уже рассмотрели. Откройте examples/tutorial/second.cc в вашем любимом редакторе. Вы уже видели достаточно кода ns‑3, чтобы понять большую часть того, что происходит в этом примере, но мы пройдемся по всему сценарию и рассмотрим некоторые из результатов.


Как и в примере first.cc (и во всех примерах ns‑3), файл начинается со строки режима emacs и строк о GPL лицензии.


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


#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"

Одной вещью, которая может быть удивительно полезной, является небольшой ASCII рисунок, которое показывает схему топологии сети, которая строится в примере. Вы найдете похожий «рисунок» в большинстве наших примеров.


В этом случае вы можете видеть, что мы собираемся расширить наш двухточечный пример (связь между узлами n0 и n1 ниже), прицепив шинную сеть с правой стороны. Обратите внимание, что это топология сети по умолчанию, вы можете варьировать количество узлов, создаваемых в локальной сети. Если вы установите nCsma в единицу, в локальной сети (канал CSMA) будет всего два узла — один обязательный узел и один «дополнительный» узел. По умолчанию есть три «дополнительных» узла, как показано ниже:


// Default Network Topology
//
//       10.1.1.0
// n0 -------------- n1   n2   n3   n4
//    point-to-point  |    |    |    |
//                    ================
//                      LAN 10.1.2.0

Затем используется пространство имен ns‑3 и определяется компонент журналирования. Все так же, как это было в first.cc, поэтому пока ничего нового.


using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("SecondScriptExample");

Основная программа начинается немного по-другому. Мы используем флаг verbose для подробного вывода, чтобы знать наверняка включены ли компоненты журналирования в UdpEchoClientApplication и UdpEchoServerApplication. Этот флаг по умолчанию имеет значение true (компоненты журналирования включены), но позволяет отключить журналирование во время регрессионного тестирования этого примера.


Мы видим знакомый подход, который позволит вам изменять количество устройств в сети CSMA через аргумент командной строки. Мы делали нечто похожее в разделе об аргументах командной строки 5.2.2, когда управляли количеством отправленных пакетов. Последняя строка гарантирует, что у вас будет хотя бы один «лишний» узел.
Код состоит из варианта ранее описанного API, поэтому вам он должен быть понятен.


bool verbose = true;
uint32_t nCsma = 3;
CommandLine cmd;
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);
cmd.Parse (argc, argv);
if (verbose)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
nCsma = nCsma == 0 ? 1 : nCsma;

На следующем шаге создаются два узла, которые мы будем связывать через соединение точка-точка. Контейнер NodeContainer используется так же, как это было сделано в first.cc.


NodeContainer p2pNodes;
p2pNodes.Create (2);

Затем мы объявляем еще один NodeContainer для хранения узлов, которые будут частью шинной сети (CSMA). Сначала мы просто создаем экземпляр самого объекта-контейнера.


NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);

Следующая строка кода получает первый узел (например, имеющий индекс один) из контейнера двухточечного узла и добавляет его в контейнер узлов, которые станут CSMA устройствами. Рассматриваемый узел в конечном итоге станет одновременно устройством точка-точка и CSMA устройством. Затем мы создаем несколько «дополнительных» узлов, которые образуют оставшуюся часть CSMA сети. Так как у нас уже есть один узел в сети CSMA — тот, что будет выступать как устройство точка-точка и CSMA устройство, количество «лишних» узлов определяется как желаемое число узлов сегменте CSMA минус один.


Следующий фрагмент кода должен быть уже знаком. Мы создаем экземпляр PointToPointHelper и устанавливаем связанные атрибуты по умолчанию так, чтобы на устройствах, созданных с помощью помощника получить передачу со скоростью пять мегабит в секунду и задержкой две миллисекунды в канале.


PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);

Затем мы создаем экземпляр NetDeviceContainer для отслеживания сетевых устройств «точка-точка» и устанавливаем устройства на узлах точка-точка.


Выше мы упоминали, что в следующих строках появится помощник для CSMA устройств и каналов. CsmaHelper работает так же, как PointToPointHelper, но он создает и подключает CSMA устройства и каналы. Обратите внимание, что в случае CSMA для пары устройство — канал, скорость передачи данных указана атрибутом channelAttribute вместо deviceAttribute. Это потому, что настоящая сеть CSMA не позволяет смешивать, устройства 10Base-T и 100Base-T в одном канале. Сначала мы устанавливаем скорость передачи данных до 100 мегабит в секунду, и затем задержку в 6560 наносекунд на распространение по каналу со скоростью света (выбрана произвольно как 1 наносекунда на фут, соответствует отрезку кабеля длиной 100 метров). Обратите внимание, что вы можете установить атрибут, используя его собственный тип данных.


CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);

Так же, как мы создали NetDeviceContainer для хранения устройств, созданных PointToPointHelper, мы создаем NetDeviceContainer для хранения устройств, созданных нашим CsmaHelper. Мы вызываем метод Install CsmaHelper для установки устройств в узлы csmaNodes NodeContainer.


Теперь у нас есть созданные узлы, устройства и каналы, но у нас нет стеков протоколов. Как в first.cc скрипте, мы будем использовать InternetStackHelper для установки этих стеков.


InternetStackHelper stack;
stack.Install (p2pNodes.Get (0));
stack.Install (csmaNodes);

Напомним, что мы взяли один из узлов контейнера p2pNodes и добавили его в контейнер csmaNodes. таким образом чтобы охватить все узлы симуляции, нам нужно только установить стеки на оставшийся узел p2pNodes и узлы в контейнере csmaNodes. Как и в примере сценария first.cc, для назначения IP-адресов интерфейсов наших устройств мы будем использовать Ipv4AddressHelper. Сначала мы используем сеть 10.1.1.0для создания двух адресов, необходимых для соединения наших устройств точка-точка.


Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);

Напомним, что мы сохраняем созданные интерфейсы в контейнере, чтобы впоследствии было проще извлекать адресную информацию для использования в настройке приложений. Теперь нам нужно назначить IP-адреса интерфейсам нашего CSMA устройства. Операция работает так же, как и для случая точка-точка, за исключением того, что мы сейчас выполняем операцию над контейнером с переменным числом CSMA устройств — помните, что мы сделали количество CSMA устройств управляемым от аргумента командной строки. Устройства CSMA в этом случае будут привязаны к IP-адресам сети10.1.2.0, как показано ниже.


address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);

Теперь у нас построена топология, но нам нужны приложения. Этот раздел будет в основном похож на раздел приложений файла first.cc, но мы собираемся создать экземпляр сервера на одном из узлов с CSMA устройством и клиент на узле, имеющем только двухточечное устройство. Сначала мы настроим эхо-сервер. Мы создаем UdpEchoServerHelper и предоставляем конструктору требуемое значение атрибута, который является номером порта сервера. Напомним, что этот порт, при желании, можно изменить позже, используя метод SetAttribute, но сейчас нам требуется подставить в конструктор конкретное значение.


UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));

Напомним, что контейнер csmaNodes содержит один из узлов, созданных для двухточечной сети, и nCsma «дополнительных» узлов. Предположим, мы хотим получить последний из «дополнительных» узлов. Нулевая запись в контейнере csmaNodes будет точка-точка. Самый простой способ это понять, так это представить, что если мы создадим один «дополнительный» CSMA узел, тогда в контейнере csmaNodes он окажется под индексом 1. Тогда, по математической индукции, если мы создадим nCsma «дополнительных» узлов, то последний узел будет с индексом nCsma. Вы это и видите в первой строке кода в Get.


Клиентское приложение настроено также, как мы это делали в примере скрипта first.cc. Опять же, мы передаем необходимые атрибуты в конструктор UdpEchoClientHelper (в данном случае это удаленный адрес и порт). Мы говорим клиенту отправлять пакеты на сервер, который мы только что установили на последнем «дополнительном» CSMA узле. Мы устанавливаем клиент на самом левом двухточечном узле, показанном на иллюстрации топологии.


UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));

Поскольку мы фактически соединили здесь две разные сети, нам нужна некоторая форма межсетевой маршрутизации. Ns‑3, чтобы помочь вам, предоставляет вам то, что мы называем глобальной маршрутизацией. Глобальная маршрутизация использует тот факт, что вся внутренняя сеть доступна в симуляции и проходит через все узлы, созданные для симуляции — она выполняет тяжелую работу по настройке маршрутизация для вас без необходимости настройки маршрутизаторов. По сути, каждый узел ведет себя так, как если бы он был маршрутизатором OSPF1, который за кулисами обменивается данными со всеми другими роутерами мгновенно и волшебно. Каждый узел генерирует объявления о состоянии канала и передает их непосредственно к глобальному диспетчеру маршрутов, который использует эту глобальную информацию для построения таблиц маршрутизации для каждого узла. Настройка этой формы маршрутизации выполняется одно строкой:


Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

Далее мы включаем трассировку pcap. Первая строка кода для включения трассировки pcap в двухточечном помощнике должна быть вам сейчас знакома. Вторая строка включает трассировку pcap в помощнике CSMA, и есть дополнительный параметр, с которым мы еще не встречались.


pointToPoint.EnablePcapAll ("second");
csma.EnablePcap ("second", csmaDevices.Get (1), true);

Сеть CSMA является многоточечной сетью. Это означает, что в общей среде передачи могут существовать несколько конечных точек (как раз наш случай). С каждой из этих конечных точек связано сетевое устройство. Есть две основных альтернативы сбору трассировочной информации в такой сети. Один из способов — создать файл трассировки для каждого сетевого устройства и хранить только пакеты, которые испускаются или получаются этим устройством. Другой способ — выбрать одно из устройств. и поместить его в неразборчивый режим (Promiscuous mode). Это единственное устройство затем «прослушивает» все пакеты в сети и сохраняет их в один pcap файл. Так работает, например, tcpdump. Последний параметр включает в CSMA помощнике захват пакетов в неразборчивом режиме.


В этом примере мы собираемся выбрать в CSMA сети одно из устройств и попросить его выполнить неразборчивый захват пакетов сети, тем самым подражая тому, как сделает tcpdump. Чтобы получить трассировку на компьютере с Linux, вы могли бы сделать что-то вроде tcpdump -i eth0. В данном случае мы указываем устройство с помощью csmaDevices.Get(1), который выбирает первое устройство в контейнере. Установка конечного параметра в значение true разрешает неразборчивый захват. Последний раздел кода просто запускает и очищает симуляцию, как в примере first.cc.


Simulator::Run ();
Simulator::Destroy ();
return 0;
}

Чтобы запустить этот пример, скопируйте скрипт-пример second.cc в рабочую директорию и используйте waf для сборки, как это вы делали с примером first.cc. Если вы находитесь в директории верхнего уровня репозитория, то просто наберите,


$ cp examples/tutorial/second.cc scratch/mysecond.cc
$ ./waf

Предупреждение: файл second.cc в качестве одного из наших регрессионных тестов, для проверки данного руководства. Т.е. исполняемый файл с именем second уже существует в проекте. Чтобы избежать путаницы, в показанном выше примере мы копируем файл second.cc с изменением имени на mysecond.cc.


Если вы неукоснительно следовали руководству (не так ли), у вас все равно будет установлена переменная NS_LOG, так, что двигаемся вперед и очищаем эту переменную и запускаем программу.


$ export NS_LOG=
$ ./waf --run scratch/mysecond

Так как мы в UDP эхо-приложениях настроили журналирование, также как мы делали в first.cc, когда вы запустите скрипт, вы увидите похожий вывод.


Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.415s)
Sent 1024 bytes to 10.1.2.4
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.2.4
Напомним, что первое сообщение «
Sent 1024 bytes to 10.1.2.4

» от UDP эхо-клиента, отправляющего пакет серверу. В этом случае сервер находится в другой сети (10.1.2.0). Второе сообщение «Received 1024 bytes from 10.1.1.1
» от UDP эхо-сервера, генерируемое при получении эхо-пакета. Финальное сообщение «Received 1024 bytes from 10.1.2.4» от эхо-клиента, указывающее, что он получило свое эхо от сервера обратно.


Если вы сейчас зайдете в директорию верхнего уровня, вы найдете три файла трассировки:


second-0-0.pcap second-1-0.pcap second-2-0.pcap

Давайте взглянем на именование этих файлов. Для всех оно имеет одинаковую форму,<Имя> - <узел> - <устройство> .pcap. Например, первый файл в списке — second-0-0.pcap это pcap трассировка от узла 0, устройства 0. Это двухточечное сетевое устройство на нулевом узле. Файл second-1-0.pcap — pcap трассировка для нулевого устройства на первом узле, также являющегося сетевым устройством точка-точка; и файл second-2-0.pcap — это pcap трассировка для нулевого устройства на втором узле. Если вы вернетесь к иллюстрации топологии в начале раздела, то увидите, что нулевой узел является самым левым узлом соединения точка-точка, а узел 1 — это узел, который выступает как устройство точка-точка, так и как CSMA устройство. Мы также видим, что узел 2 является первым «дополнительным» узлом в CSMA сети, и его устройство 0 было выбрано в качестве устройства для трассировки в неразборчивом режиме.


Теперь давайте проследим за движением эхо-пакета по сети. Сначала выполните tcpdump файла трассировки для самого левого узла точка-точка — 0.


$ tcpdump -nn -tt -r second-0-0.pcap

Вы должны увидеть содержимое файла pcap:


reading from file second-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Первая строка дампа ожидаемо указывает, что тип связи — PPP (точка-точка)3. Затем вы видите эхо-пакет, покидающий узел 0 и через устройство, связанное с IP-адресом
10.1.1.1, направляется на IP-адрес 10.1.2.4 (самый правый CSMA узел). Этот пакет будет перемещаться по каналу «точка-точка» и приниматься устройством сети «точка-точка» на первом узле. Давайте взглянем:
$ tcpdump -nn -tt -r second-1-0.pcap
Теперь вы должны увидеть вывод pcap трассировки на другой стороне двухточечного линка:


reading from file second-1-0.pcap, link-type PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Здесь мы видим, что тип линка также PPP, как и следовало ожидать. Вы видите пакет с IP-адреса 10.1.1.1 (который был отправлено в 2.000000 секунд) в направлении IP-адреса 10.1.2.4 на этом интерфейсе. Теперь внутри этого узла пакет будет переадресован на интерфейс CSMA, и мы должны увидеть, что он выскочил на это устройство, направляясь к его конечному пункту назначения.


Вспомним, что мы выбрали узел 2 в качестве неразборчивого анализатора для CSMA сети, поэтому давайте взглянем на second-2-0.pcapи посмотрим пакет там.


$ tcpdump -nn -tt -r second-2-0.pcap

Теперь вы должны увидеть неразборчивый дамп устройства 0 на узле 2:


reading from file second-2-0.pcap, link-type EN10MB (Ethernet)
2.007698 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.007710 ARP, Reply 10.1.2.4 is-at 00:00:00:00:00:06, length 50
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, length 50
2.013828 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Как видите, тип соединения теперь «Ethernet». Однако появилось что-то новое. Шинная сеть нуждается в ARP, протоколе разрешения адресов. Узел знает, что ему нужно отправить пакет на IP-адрес 10.1.2.4, но он не знает MAC-адрес соответствующего узла. Он вещает в CSMA сети (ff: ff: ff: ff: ff: ff), запрашивая устройство которое имеет IP-адрес 10.1.2.4. В этом случае самый правый узел отвечает, что он находится по MAC-адресу 00: 00: 00: 00: 00: 06. Обратите внимание, что второй узел напрямую не участвует в этом обмене, но отслеживает сеть и сообщает обо всем трафике что видит. Этот обмен виден в следующих строках,


2.007698 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.007710 ARP, Reply 10.1.2.4 is-at 00:00:00:00:00:06, length 50

Затем, устройство 1 узла 1 идет дальше и отправляет эхо-пакет на UDP эхо-сервер по IP-адресу 10.1.2.4.


2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024

Сервер получает эхо-запрос и переворачивает пакет, пытаясь отправить его обратно источнику. Сервер знает, что этот адрес находится в другой сети, которую он может достичь через IP-адрес 10.1.2.1. Это ему известно потому, что мы инициализировали глобальную маршрутизацию, и она выяснила все это для нас. Но узел эхо-сервера не знает MAC-адрес первого CSMA узла, поэтому он должен выполнить ARP запрос, как и первый CSMA узел.


2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, length 50
2.013828 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50

Затем сервер отправляет эхо-сигнал обратно на узел пересылки.


2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Оглядываясь назад, на самый правый узел двухточечного линка,


$ tcpdump -nn -tt -r second-1-0.pcap

в последней строке дампа трассировки вы можете видеть отраженный пакет, возвращаемый по двухточечному линку.


reading from file second-1-0.pcap, link-type PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Наконец, вы можете снова взглянуть на узел, который вызвал эхо


$ tcpdump -nn -tt -r second-0-0.pcap

и увидеть, что отраженный пакет возвращается обратно к источнику за 2,017607 секунд,


reading from file second-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024

Напоследок напомним, что мы добавили возможность управления количеством CSMA устройств в симуляции с помощью аргумента командной строки. Вы можете изменить этот аргумент так же, как мы меняли количество пакетов в примере first.cc. Попробуйте запустить программу с четырьмя дополнительными устройствами:


$ ./waf --run "scratch/mysecond --nCsma=4"

Теперь вы должны увидеть,


Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.405s)
At time 2s client sent 1024 bytes to 10.1.2.5 port 9
At time 2.0118s server received 1024 bytes from 10.1.1.1 port 49153
At time 2.0118s server sent 1024 bytes to 10.1.1.1 port 49153
At time 2.02461s client received 1024 bytes from 10.1.2.5 port 9

Обратите внимание, что теперь эхо-сервер перенесен на последний из CSMA узлов, адрес которого 10.1.2.5 вместо случая по умолчанию, 10.1.2.4.


Вполне возможно, что вы не будете удовлетворены файлом трассировки, созданным наблюдателем в сети CSMA. Если вас не интересует трафик с других устройств сети, вы можете получить трассировку с одного устройства. Это делается довольно легко.
Чтобы быть более конкретными, давайте посмотрим на scratch/mysecond.cc и добавим этот код. Помощники ns‑3 предоставляют методы, которые в качестве параметров принимают номер узла и номер устройства. Идем дальше и заменим вызовы EnablePcap вызовами ниже.


pointToPoint.EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("second", csmaNodes.Get (nCsma)->GetId (), 0, false);
csma.EnablePcap ("second", csmaNodes.Get (nCsma-1)->GetId (), 0, false);

Мы знаем, что хотим создать файл pcap с базовым именем «second», и мы также знаем, что в обоих случаях нас интересует устройство 0, поэтому эти параметры не очень интересны.


Чтобы получить номер узла, у вас есть два варианта: первый, узлы нумеруются монотонно в возрастающем порядке начиная с нуля в том порядке, в котором вы их создаете. Один из способов получить номер узла — выяснить это число «вручную», опираясь на знание того, в каком порядке вы создавали узлы. Если вы посмотрите на иллюстрацию топологии сети в начале файла, которую мы сделали для вас, то сможете увидеть, что последний CSMA узел будет иметь номер узла равный
nCsma + 1. Такой подход может стать раздражающе сложным в больших симуляциях.


Альтернативный способ, который мы здесь применим, состоит в том, чтобы использовать указатели на объекты Node ns‑3, которые содержатся в NodeContainer. Объект Node имеет метод GetId, который возвращает идентификатор этого узла, который является номером узла, который мы ищем. Давайте посмотрим на Doxygen для Node и найдем этот метод, который в коде ядра ns‑3 находится глубже, чем мы заглядывали до сих пор. Но иногда вы должны усердно искать полезные вещи.


Перейдите к документации Doxygen для вашего релиза (напомним, что вы можете найти ее на веб-сайте проекта). Вы можете добраться до документации по Node, просматривая вкладку «Классы» и прокручивая «Список классов», пока не найдете ns3::Node. Выберите ns3::Node, и вы попадете в документацию по классу Node. Если вы прокрутите до метода GetId и выберете его, то попадете в подробную документацию по методу. С помощью метода GetId может значительно облегчить определение номеров узлов в сложных топологиях.


Давайте удалим старые файлы трассировки из директории верхнего уровня, чтобы избежать путаницы в том, что происходит,


$ rm *.pcap
$ rm *.tr

Если вы создадите новый скрипт и запустите симуляцию с аргументом
nCsma=100,


$ ./waf --run "scratch/mysecond --nCsma=100"

вы увидите следующий вывод:


Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.407s)
At time 2s client sent 1024 bytes to 10.1.2.101 port 9
At time 2.0068s server received 1024 bytes from 10.1.1.1 port 49153
At time 2.0068s server sent 1024 bytes to 10.1.1.1 port 49153
At time 2.01761s client received 1024 bytes from 10.1.2.101 port 9

Обратите внимание, что теперь эхо-сервер расположен по адресу 10.1.2.101
, что соответствует наличию 100 «дополнительных» узлов CSMA с эхо-сервером на последнем. Если вы запросите список файлов pcap в директории верхнего уровня, то увидите,


second-0-0.pcap second-100-0.pcap second-101-0.pcap

Файл трассировки second-0-0.pcap относится к «самому левому» двухточечному устройству, которое является источником эхо-пакетов. Файл second-101-0.pcap соответствует крайнему правому устройству CSMA, в котором находится эхо-сервер. Вы возможно, заметили, что последний параметр вызова для включения трассировки pcap на узле эхо-сервера был false. Этот означает, что трассировка, собранная на этом узле, была в неразборчивом режиме.


Чтобы проиллюстрировать разницу между неразборчивыми и разборчивыми трассировками, мы также попросили разборчивую трассировку для ближайшего к последнему узла. Продолжим и посмотрим на tcpdump для second-100-0.pcap.


$ tcpdump -nn -tt -r second-100-0.pcap

Теперь вы можете видеть, что узел 100 действительно является наблюдателем в эхо-обмене. Единственные пакеты, которые он получает, это ARP-запросы, которые передаются по всей CSMA сети.


reading from file second-100-0.pcap, link-type EN10MB (Ethernet)
2.006698 ARP, Request who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101, length 50

Теперь взгляните на tcpdump для second-101-0.pcap.


$ tcpdump -nn -tt -r second-101-0.pcap

Теперь вы можете видеть, что узел 101 действительно является участником эхо-обмена.


reading from file second-101-0.pcap, link-type EN10MB (Ethernet)
2.006698 ARP, Request who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.006698 ARP, Reply 10.1.2.101 is-at 00:00:00:00:00:67, length 50
2.006803 IP 10.1.1.1.49153 > 10.1.2.101.9: UDP, length 1024
2.013803 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101, length 50
2.013828 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50
2.013828 IP 10.1.2.101.9 > 10.1.1.1.49153: UDP, length 1024

6.2 Модели, атрибуты и реальность


Это удобный момент, чтобы сделать небольшое отступление и сделать важное замечание. Это может быть. а может и не быть очевидным для вас, но всякий раз, когда кто-то использует симуляцию, важно точно понимать, что моделируется, а что нет. Например, заманчиво думать об устройствах и каналах CSMA, использованных в предыдущем разделе, как будто они были настоящими Ethernet устройствами; и ожидать, что результат моделирования напрямую отразит то, что произойдет в реальном Ethernet. Это не так.


Модель, по определению, является абстракцией реальности. В конечном счете ответственность в определении так называемого «степень точности» и «области применимости» моделирования в целом и его составных частей лежит на авторе сценария симуляции.


В некоторых случаях, например, в Csma, довольно просто определить, что не моделируется. Читая описание модели (csma.h) вы можете обнаружить, что в модели CSMA нет обнаружения коллизий, и решить, насколько допустимо её использование или какие оговорки вам придется включить в ваши результаты моделирования.


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


Как вы видели, ns‑3 предоставляет атрибуты, которые пользователь может легко установить для изменения поведения модели. Рассмотрим два атрибута CsmaNetDevice: Mtu и EncapsulationMode. Атрибут Mtu указывает устройству максимальный размер передаваемого пакета (Maximum Transmission Unit). Это размер самого большого протокольного блока данных ( PDU), который устройство может отправить.


В CsmaNetDevice значение MTU по умолчанию составляет 1500 байт. Это значение по умолчанию соответствует числу, устанавливаемому в RFC 894, «Стандарт для передачи IP-дейтаграмм по сетям Ethernet». Фактически число получено из максимального размера пакета для сетей 10Base5 (полная спецификация Ethernet) — 1518 байт. Если вы вычтете накладные расходы на инкапсуляцию в пакетах Ethernet DIX4 (18 байт), в результате получите максимально возможный размер данных (MTU) 1500 байт. Также можно обнаружить, что MTU для сетей IEEE 802.3 составляет 1492 байта. Это потому, что инкапсуляция LLC/SNAP добавляет в пакет дополнительные восемь байтов служебной информации. В обоих случаях базовое оборудование может отправлять только 1518 байт, но размер данных отличается.


Чтобы установить режим инкапсуляции, CsmaNetDevice предоставляет атрибут, называемый EncapsulationMode, который может принимать значения Dix или Llc. Они соответствуют кадру Ethernet или LLC/SNAP соответственно.


Если оставить Mtu в 1500 байт и изменить режим инкапсуляции на Llc, результатом будет сеть, которая инкапсулирует 1500-байтовые PDU с кадрами LLC/SNAP, что приводит к пакетам по 1526 байтов. Для многих сетей это будет недопустимо, поскольку они могут передавать в пакете максимум 1518 байт. Это приведет к моделированию, которое вопреки вашим ожиданиям скорее всего не достаточно точно отразит реальность.


Теперь, еще усложним картину, существуют jumbo (гигантские) кадры (1500 < MTU ≤ 9000 байт) и super-jumbo (супер-гигантские) (MTU > 9000) байт) кадры, которые официально не разрешены IEEE, но доступны в некоторых высокоскоростных (гигабитных) сетях и сетевых адаптерах. Можно оставить режим инкапсуляции установленным на Dix и установить атрибут Mtu на CsmaNetDevice до 64000 байт — даже несмотря на то, что у связанного с ним CsmaChannel DataRate был установлен на 10 мегабит в секунду. По существу, это будет модель Ethernet коммутатора сети 10Base5 с отводами «зуб вампира» в стиле 1980-х годов, который поддерживает супер-гигантские дейтаграммы. Это, конечно, не то, что когда-либо могло быть сделано, и вряд ли когда-либо будет осуществлено, но вам легко будет «наконфигурировать» такое.


В предыдущем примере для создания симуляции вы использовали командную строку, в которой было 100 узлов Csma. Вы могли бы так же легко создать симуляцию с 500 узлами. Если бы вы на самом деле моделировали сеть 10Base5 с отводами, где максимальная длина полнофункционального Ethernet-кабеля составляет 500 метров, а минимальное расстояние между ответвлениями — 2,5 метра. То это бы означало, что в реальной сети могло бы быть не более 200 подключений. Таким образом, вам довольно легко построить и смоделировать нереализуемую сеть. Это означает, что ценность результатов проводимого вами моделирования зависит от того, насколько реальные вещи вы пытаетесь моделировать.


Подобные ситуации могут возникнуть во многих местах ns‑3 и в любом другом симуляторе. Например, вы можете расположить узлы таким образом, что они в одно и тоже врем будут занимать одну и ту же точку пространства или настроить усилители или уровни шума, таким образом, что будут нарушены основные законы физики.
Ns‑3 обычно поддерживает гибкость, и многие модели позволяют свободно менять атрибуты, не пытаясь заставить вас следовать каким-то ограничениям или конкретным спецификациям. Из этого следует вывод, что ns‑3 предоставляет вам сверхгибкую базу для экспериментов. От вас зависит, что вы просите систему сделать, насколько создаваемые вами симуляции и результаты имеют связь с реальностью.


6.3 Построение топологии беспроводной сети


В этом разделе, для расширения наших познаний в сетевых устройствах и каналах ns‑3, мы охватим пример беспроводной сети. Ns‑3 предоставляет набор моделей 802.11, которые стремятся обеспечить точную реализацию MAC уровня спецификации 802.11 и «не очень медленная» модель PHY-уровня спецификации 802.11a.


В этом разделе мы увидим топологических помощников для Wi-Fi эквивалентных тем, что мы использовали при построении топологий точка-точка и CSMA. Применение и работа этих помощников должны выглядеть для вас знакомо.


Мы предоставляем пример сценария в нашей директории examples/tutorial. Этот пример основан на скрипте second.cc с добавлением сети Wi-Fi. Чтобы продолжить, открываем examples/tutorial/third.cc в вашем любимом редакторе. Вы уже видели достаточное количество кода ns‑3, чтобы понять большую часть того, что происходит в этом примере, но есть несколько новых вещей, поэтому мы пройдемся по всему сценарию и рассмотрим некоторые результаты.


Как и в примере second.cc (и во всех примерах ns‑3), файл начинается со строки режима emacs и слов лицензии GPL.


Взгляните на ASCII иллюстрацию (показанную ниже), она показывает топологию сети по умолчанию, построенную в примере. Вы можете видеть, что мы собираемся расширить наш пример, подключив беспроводную сеть с левой стороны. Напоминаем, что это топология сети по умолчанию, но вы можете изменять количество узлов, создаваемых в проводной и беспроводной сетях. Также как в сценарии second.cc, если вы измените nCsma, это даст вам ряд «лишних» CSMA узлов. Точно так же вы можете поступить и с nWifi, для указания нужного в симуляции количества STA узлов (станций). В беспроводной сети всегда будет один узел AP (точка доступа). По умолчанию есть три «дополнительных» CSMA узла и три беспроводных STA узла.
Код начинается с загрузки подключаемых файлов модулей так же, как это делается в примере second.cc. Есть пара новых, подключающих соответственно модуль Wi-Fi и модуль мобильности, которые мы обсудим ниже.


#include "ns3/core-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/network-module.h"
#include "ns3/applications-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"

Иллюстрация топологии сети выглядит следующим образом:


// Default Network Topology
//
// Wifi 10.1.3.0
//                 AP
//  *    *    *    *
//  |    |    |    |     10.1.1.0
// n5   n6   n7   n0 -------------- n1   n2   n3   n4
//                   point-to-point  |    |    |    |
//                                   ================
//                                     LAN 10.1.2.0

Вы можете видеть, что мы добавляем новое сетевое устройство к узлу с левой стороны двухточечного линка, который становится точкой доступа к беспроводной сети. Ряд беспроводных узлов STA создан для наполнения новой сети
10.1.3.0, как показано на левой стороне иллюстрации. После иллюстрации задействуется пространство имен ns‑3 и определяется компонент журналирования. Это все должно уже быть знакомо.


using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample");

Основная программа начинается так же, как second.cc, с добавления некоторых параметров командной строки для включения или отключения компонентов журналирования и для изменения количества создаваемых устройств.


bool verbose = true;
uint32_t nCsma = 3;
uint32_t nWifi = 3;
CommandLine cmd;
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi);
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);
cmd.Parse (argc,argv);
if (verbose)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}

Как и во всех предыдущих примерах, следующим шагом является создание двух узлов, которые мы будем соединять линком точка-точка.


NodeContainer p2pNodes;
p2pNodes.Create (2);

Далее мы видим старого друга. Создается экземпляр PointToPointHelper и устанавливаются соответствующие атрибуты по умолчанию таким образом, чтобы на создаваемых помощником устройствах передатчики имели скорость пять мегабит в секунду, а у создаваемых каналов задержка была две миллисекунды. Затем мы устанавливаем устройства на узлы и канал между ними.


PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);

Затем мы объявляем еще один NodeContainer для хранения узлов, которые будут частью шинной сети (CSMA).


NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);

Следующая строка кода получает первый узел (например, имеющий индекс один) из контейнера двухточечного узла и добавляет его в контейнер узлов, которые получат устройства CSMA. Рассматриваемый узел будет содержать устройство точка-точка и CSMA устройство. Затем мы создаем несколько «дополнительных» узлов, которые образуют оставшуюся часть CSMA сети.


Затем, мы создаем экземпляр CsmaHelper и устанавливаем его атрибуты, также как мы это делали в предыдущем примере. Мы создаем NetDeviceContainer для отслеживания созданных сетевых CSMA устройств, а затем инсталлируем CSMA устройства на выбранные узлы.


CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);

Далее мы собираемся создать узлы, которые будут частью сети Wi-Fi. Мы создадим то количество узлов «станций», какое указано в аргументе командной строки, и мы будем использовать «самый левый» узел двухточечного линка как узел для точки доступа.


NodeContainer wifiStaNodes;
wifiStaNodes.Create (nWifi);
NodeContainer wifiApNode = p2pNodes.Get (0);

Следующий фрагмент кода создает Wi-Fi устройства и канал связи Wi-Fi между этими узлами. Сначала мы настраиваем помощников PHY и канала:


YansWifiChannelHelper channel = YansWifiChannelHelper::Default ();
YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();

Для простоты, этот код для PHY-уровня и модели канала использует конфигурирование по умолчанию, с помощью методов
YansWifiChannelHelper::Default и YansWifiPhyHelper::Default, которые описаны в документации Doxygen API. Как только эти объекты будут созданы, мы создаем объект канала и связываем его с нашим менеджером объектов PHY уровня, гарантируя тем самым, что все объекты PHY уровня, созданные YansWifiPhyHelper используют один и тот же базовый канал, а значит и общую беспроводную среду, где они могут коммуницировать и интерферировать:


phy.SetChannel (channel.Create ());

Как только PHY помощник настроен, мы можем сосредоточиться на MAC уровне. Здесь мы решили работать с non-Qos MAC. Для установки параметров MAC используется объект WifiMacHelper.


WifiHelper wifi;
wifi.SetRemoteStationManager ("ns3::AarfWifiManager");
WifiMacHelper mac;

Метод SetRemoteStationManager сообщает помощнику тип используемого алгоритма управления скоростью. Он просит помощника использовать алгоритм AARF (Adaptive AutoRate Fallback) — подробности, конечно, доступны в Doxygen.


Затем мы настраиваем тип MAC, SSID (Service Set Identification)сети, которую мы хотим настроить, и отключаем активное зондирование:


Ssid ssid = Ssid ("ns-3-ssid");
mac.SetType ("ns3::StaWifiMac",
  "Ssid", SsidValue (ssid),
  "ActiveProbing", BooleanValue (false));

Этот код сначала создает объект идентификатора набора служб (SSID) 802.11, который будет использоваться для установки значения «Ssid», атрибута реализации MAC уровня. Атрибут «ns3::StaWifiMac» определяет особый тип MAC уровня, который будет создан помощником. Атрибут «QosSupported» для объектов WifiMacHelper по умолчанию имеет значение false. Сочетание этих двух конфигураций означает, что следующий созданный экземпляр MAC будет соответствовать станции (STA) без QoS и без AP в инфраструктуре BSS (то есть в BSS с AP). Наконец, Атрибут «ActiveProbing» имеет значение false. Это означает, что MAC, созданные этим помощником не будут отправлять тестовые запросы. После того, как все параметры станции полностью настроены, как на MAC уровне, так и на PHY уровне, мы теперь можем вызвать знакомый нам метод установки для создания устройств Wi-Fi этих станций:


NetDeviceContainer staDevices;
staDevices = wifi.Install (phy, mac, wifiStaNodes);

Мы настроили Wi-Fi для всех наших STA узлов, и теперь нам нужно настроить AP узел (точку доступа). Чтобы отразить требования AP, мы начнем этот процесс, с изменения атрибутов по умолчанию для WifiMacHelper.


mac.SetType ("ns3::ApWifiMac",
"Ssid", SsidValue (ssid));

В этом случае WifiMacHelper будет создавать MAC уровень
«ns3::ApWifiMac», причем последний указывает, что должен быть создан экземпляр MAC, настроенный как AP. Мы не меняем настройки по умолчанию у атрибута «QosSupported», поэтому он остается false — отключение поддержки QoS на созданных точках доступа в стиле 802.11e/WMM. Следующие строки создают одну точку доступа, которая использует тот же набор атрибутов PHY уровня (и канал), что и для станций:


NetDeviceContainer apDevices;
apDevices = wifi.Install (phy, mac, wifiApNode);

Теперь мы добавим модель мобильности. Мы хотим, чтобы STA узлы были подвижными и бродили внутри ограничивающего поля, а узел AP мы хотим сделать стационарным. Чтобы облегчить работу, мы используем MobilityHelper. Сначала создаем экземпляр объекта MobilityHelper и устанавливаем некоторые атрибуты, управляющие функциональностью «распределителя положений».


MobilityHelper mobility;
mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
"MinX", DoubleValue (0.0),
"MinY", DoubleValue (0.0),
"DeltaX", DoubleValue (5.0),
"DeltaY", DoubleValue (10.0),
"GridWidth", UintegerValue (3),
"LayoutType", StringValue ("RowFirst"));

Этот код указывает помощнику мобильности использовать для первоначального размещения STA узлов двумерную сетку. Не стесняйтесь исследовать Doxygen для класса ns3::GridPositionAllocator, чтобы точно понять, что происходит. Мы разместили наши узлы на начальной сетке, но теперь нам нужно рассказать им, как двигаться. Мы выбираем модель RandomWalk2dMobilityModel, в которой узлы перемещаются в случайном направлении со случайной скоростью внутри ограничительной рамки.


mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
"Bounds", RectangleValue (Rectangle (-50, 50, -50, 50)));

Теперь мы говорим MobilityHelper установить модель мобильности на STA узлах.


mobility.Install (wifiStaNodes);

Мы хотим, чтобы точка доступа во время симуляции оставалась в фиксированном положении. Мы получаем это, устанавливая для её узла модель мобильности


ns3::ConstantPositionMobilityModel:
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobility.Install (wifiApNode);

Теперь у нас есть созданные узлы, устройства, каналы и модели мобильности, выбранные для узлов Wi-Fi. Но у нас отсутствуют стеки протоколов. Как и ранее, для их установки мы воспользуемся InternetStackHelper.


InternetStackHelper stack;
stack.Install (csmaNodes);
stack.Install (wifiApNode);
stack.Install (wifiStaNodes);

Как и в примере сценария second.cc, мы будем использовать Ipv4AddressHelper для назначения IP-адресов интерфейсов наших устройств. Сначала мы используем сеть
10.1.1.0 для создания двух адресов, необходимых для соединения наших устройства точка-точка. Затем мы используем сеть 10.1.2.0 для назначения адресов CSMA сети, а затем мы назначаем адреса из сети 10.1.3.0 для STA устройств и точки доступа в беспроводной сети.


Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);
address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);
address.SetBase ("10.1.3.0", "255.255.255.0");
address.Assign (staDevices);
address.Assign (apDevices);

Мы помещаем эхо-сервер в «самый правый» узел на иллюстрации в начале файла. Мы делали так ранее.


UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));

И мы помещаем эхо-клиент на последний созданный нами STA узел, нацеливая его на сервер в CSMA сети. Мы уже видели подобные действия раньше.


UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
ApplicationContainer clientApps =
echoClient.Install (wifiStaNodes.Get (nWifi - 1));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));

Поскольку мы построили здесь объединение сетей, то нам нужно включить межсетевую маршрутизацию, как мы это делали в примере сценария second.cc.


Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

Некоторых пользователей может удивить то, что созданная нами симуляция никогда не остановится «естественным образом». Этот потому, что мы попросили беспроводную точку доступа генерировать биконы ( beacon пакеты). Она будет генерировать биконы постоянно, и это приведет к тому, что в симуляторе будут непрерывно планироваться новые события. Поэтому мы должны сказать симулятору остановиться, даже если им могут быть запланированы события для генерации очередного бикона. Следующая строка кода говорит симулятору остановиться, чтобы бы мы не симулировали биконы в бесконечном цикле.


Simulator::Stop (Seconds (10.0));

Мы создаем трассировку, достаточную для охвата всех трех сетей:


pointToPoint.EnablePcapAll ("third");
phy.EnablePcap ("third", apDevices.Get (0));
csma.EnablePcap ("third", csmaDevices.Get (0), true);

Эти три строки кода начнут трассировку pcap на обоих точечных узлах, которые служат нашей магистралью, запустят случайную трассировку (мониторинг) в Wi-Fi и в CSMA сетях. Это позволит нам увидеть весь трафик с минимальным количеством файлов трассировки.
Наконец, мы на самом деле запускаем симуляцию, очищаем и затем выходим из программы.


Simulator::Run ();
Simulator::Destroy ();
return 0;
}

Для запуска этого примера необходимо скопировать пример сценария third.cc в рабочую директорию и использовать для сборки Waf, как мы это делали с примером second.cc. Если вы находитесь в директории верхнего уровня репозитория, то напечатайте,


$ cp examples/tutorial/third.cc scratch/mythird.cc
$ ./waf
$ ./waf --run scratch/mythird

Опять же, поскольку мы настроили UDP эхо-приложения так же, как и в сценарии second.cc, вы увидите похожий вывод.


Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.407s)
At time 2s client sent 1024 bytes to 10.1.2.4 port 9
At time 2.01796s server received 1024 bytes from 10.1.3.3 port 49153
At time 2.01796s server sent 1024 bytes to 10.1.3.3 port 49153
At time 2.03364s client received 1024 bytes from 10.1.2.4 port 9

Напомним, что первое сообщение «sent 1024 bytes to 10.1.2.4» — это UDP эхо-клиент, отправляющий пакет сервер. В этом случае клиент находится в беспроводной сети (10.1.3.0). Второе сообщение «received 1024 bytes from 10.1.3.3» от UDP эхо-сервера, генерируемое при получении эхо-пакета. Наконец сообщение «received 1024 bytes from 10.1.2.4» от эхо-клиента, указывающее, что он получил своё эхо обратно с сервера. Если вы сейчас зайдете в директорию верхнего уровня, вы найдете четыре файла трассировки этой симуляции, два для узла 0 и два для узла 1:


third-0-0.pcap third-0-1.pcap third-1-0.pcap third-1-1.pcap

Файл «third-0-0.pcap» соответствует устройству «точка-точка» на нулевом узле — левой стороне опорной сети («backborn»). Файл «third-1-0.pcap» соответствует устройству точка-точка на первом узле — правой стороне опорной сети сети. Файл «Third-0-1.pcap» — это неразборчивая трассировка (в режиме монитора) из сети Wi-Fi и файл «third-1-1.pcap» будет неразборчивая трассировка CSMA сети. Можете ли вы проверить это, инспектируя код?
Поскольку эхо-клиент находится в сети Wi-Fi, начнем с него. Давайте посмотрим на неразборчивую трассировку (режим монитора), которую мы захватили в этой сети.


$ tcpdump -nn -tt -r third-0-1.pcap

Вы должны увидеть wifi-подобное содержимое, которое вы не видели здесь ранее:


reading from file third-0-1.pcap, link-type IEEE802_11 (802.11)
0.000025 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.000308 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000324 Acknowledgment RA:00:00:00:00:00:08
0.000402 Assoc Response AID(0) :: Successful
0.000546 Acknowledgment RA:00:00:00:00:00:0a
0.000721 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000737 Acknowledgment RA:00:00:00:00:00:07
0.000824 Assoc Response AID(0) :: Successful
0.000968 Acknowledgment RA:00:00:00:00:00:0a
0.001134 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.001150 Acknowledgment RA:00:00:00:00:00:09
0.001273 Assoc Response AID(0) :: Successful
0.001417 Acknowledgment RA:00:00:00:00:00:0a
0.102400 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.204800 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.307200 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS

Теперь видно, что тип связи теперь 802.11, как и следовало ожидать. Вы уже сможете понять, что происходит в этой трассировке, и найти IP-пакеты эхо-запросов и ответов. Мы оставляем вам полный разбор дампа трассировки как упражнение. Теперь посмотрите на файл pcap для левой части линка «точка-точка»,


$ tcpdump -nn -tt -r third-0-0.pcap

Опять же, вы должны увидеть отчасти знакомое содержимое:


reading from file third-0-0.pcap, link-type PPP (PPP)
2.008151 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024
2.026758 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024

Это эхо-пакет, идущий слева направо (от Wi-Fi до CSMA) и обратно через линию «точка-точка». Теперь посмотрите на файл pcap с правой стороны линка «точка-точка»,


$ tcpdump -nn -tt -r third-1-0.pcap

Опять же, вы должны увидеть знакомое содержимое:


reading from file third-1-0.pcap, link-type PPP (PPP)
2.011837 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024

Это также эхо-пакет, идущий слева направо (от Wi-Fi до CSMA) и обратно через линк точка-точка с немного другими временами, чем вы могли ожидать.
Эхо-сервер находится в CSMA сети, давайте посмотрим на неразборчивую трассировку там:


$ tcpdump -nn -tt -r third-1-1.pcap

Вы должны увидеть знакомое содержимое:


reading from file third-1-1.pcap, link-type EN10MB (Ethernet)
2.017837 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.017861 ARP, Reply 10.1.2.4 is-at 00:00:00:00:00:06, length 50
2.017861 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024
2.022966 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, length 50
2.022966 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024

Оно должно быть понятным. Если вы забыли, то вернитесь и посмотрите обсуждение примера second.cc. Это та же последовательность.


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


Как упоминалось в главе 5, система трассировки ns‑3 разделена на источники трассировки и приемники трассировки, и мы предоставляем функции для их соединения. Для инициации событий трассировки мы будем использовать дефолтный источник трассировки изменений модели мобильности. Нам нужно написать трассировщик для подключения к этому источнику, который будет отображать информация для нас. Несмотря на сложное описание, все довольно просто. Прямо перед основной программой в сценарий scratch/mythird.cc (т.е. сразу после оператора
NS_LOG_COMPONENT_DEFINE), добавьте следующую функцию:


void
CourseChange (std::string context, Ptr<const MobilityModel> model)
{
Vector position = model->GetPosition ();
NS_LOG_UNCOND (context <<
" x = " << position.x << ", y = " << position.y);
}

Этот код просто извлекает информацию о положении из модели мобильности и записывает x и y положения узла. Мы организуем программу таким образом, чтобы эта функция вызывалась каждый раз, когда беспроводной узел с эхо-клиентом меняет свою позицию. Мы сделаем это с помощью функции Config::Connect. Добавьте в скрипт следующие строки кода перед вызовом Simulator::Run.


std::ostringstream oss;
oss <<
"/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () <<
"/$ns3::MobilityModel/CourseChange";
Config::Connect (oss.str (), MakeCallback (&CourseChange));

Здесь мы создаем строку, содержащую путь трассировки пространства имен события, к которому мы хотим подключиться. Во-первых, используя как описано ранее метод GetId, мы должны выяснить, какой узел нам нужен. Если использовано число CSMA и беспроводных узлов заданное по умолчанию, это будет седьмой узел и путь пространства имен трассировки к модели мобильности будет выглядеть,
/NodeList/7/$ns3::MobilityModel/CourseChange.


Основываясь на обсуждении в разделе трассировки, вы можете сделать вывод, что этот путь трассировки ссылается на седьмой узел в глобальном NodeList. Он определяет то, что называется агрегированным объектом типа ns3::MobilityModel. Префикс в виде знака доллара подразумевает, что MobilityModel агрегируется на седьмом узле. Последний элемент пути означает, что мы подключились к событию «CourseChange» этой модели.


Мы устанавливаем связь между источником трассировки в узле 7 и нашим приемником трассировки, вызывая Config::Connect и предавая путь пространства имен. Как только это будет сделано, каждое событие изменения курса на седьмом узле будет подключено к нашему приемнику трассировки, который в свою очередь распечатает новую позицию.


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


'build' finished successfully (5.989s)
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.3841, y = 0.923277
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.2049, y = 1.90708
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.8136, y = 1.11368
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.8452, y = 2.11318
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.9797, y = 3.10409
At time 2s client sent 1024 bytes to 10.1.2.4 port 9
At time 2.01796s server received 1024 bytes from 10.1.3.3 port 49153
At time 2.01796s server sent 1024 bytes to 10.1.3.3 port 49153
At time 2.03364s client received 1024 bytes from 10.1.2.4 port 9
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.3273, y = 4.04175
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.013, y = 4.76955
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.4317, y = 5.67771
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.4607, y = 5.91681
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.0155, y = 6.74878
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.0076, y = 6.62336
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.6285, y = 5.698
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.32, y = 4.97559
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.1134, y = 3.99715
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.8359, y = 4.68851
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.5953, y = 3.71789
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.7595, y = 4.26688
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.7629, y = 4.34913
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.2292, y = 5.19485
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.2344, y = 5.09394
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.3601, y = 4.60846
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.40025, y = 4.32795
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.14292, y = 4.99761
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.08299, y = 5.99581
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.26068, y = 5.42677
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.35917, y = 6.42191
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.66805, y = 7.14466
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.71414, y = 6.84456
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.42489, y = 7.80181

6.4 Очереди в ns-3


Выбор дисциплин очередей в ns‑3 может оказать большое влияние на производительность, и для пользователей важно понимать, что установлено по умолчанию, как эти настройки изменить и как наблюдать за производительностью.
Архитектурно, ns‑3 отделяет уровень устройства от уровней IP или уровней управления трафиком Интернет хоста. Начиная с недавних релизов ns‑3, исходящие пакеты, прежде чем достичь объекта канала, пересекают два уровня очередей. Первый встреченный уровень очередей — это тот, что в ns‑3 называется «уровнем управления трафиком»; здесь активное управление очередью (RFC7567) и расстановка приоритетов из-за качества обслуживания (QoS) осуществляется независимо от устройства посредством использования дисциплин очередей. Второй уровень очередей обычно находится в объектах NetDevice. Разные устройства (например, LTE, Wi-Fi) имеют разные реализации этих очередей. Этот двухслойный подход отражает то, что происходит на практике, (программные очереди, обеспечивающие приоритеты, и аппаратные очереди, определенные типом линка). На практике, это может быть еще сложнее. Например, протоколы разрешения адресов имеют небольшую очередь. Wi-Fi в Linux имеет четыре слоя очередей (https://lwn.net/Articles/705884/).


Уровень управления трафиком эффективен только в том случае, если NetDevice уведомляет его о том, что очередь устройства заполнена, чтобы уровень управления трафиком мог прекратить отправку пакетов в NetDevice. В противном случае отставание дисциплин очередей всегда нулевое, и они неэффективны. В настоящее время, управление потоком, то есть возможность уведомления уровня управления трафиком, поддерживается следующими NetDevices, они используют для хранения пакетов объекты Queue (или объекты подклассов Queue):


  • Точка-точка
  • Csma
  • Wi-Fi
  • SimpleNetDevice
    На производительность дисциплин очередей, используемых NetDevices, сильно влияет их размер. В настоящее время, в ns‑3 очереди по умолчанию не подстраиваются автоматически под настроенные свойства линка (пропускная способность, задержка) и обычно, это самые простые варианты (например, FIFO с отбрасыванием новых пакетов (drop tail), для которых не хватает места в очереди). Тем не менее, размер очередей может динамически настраиваться путем включения BQL (Byte Queue Limits), алгоритм реализован в ядре Linux для регулирования размера очередей устройств в целях борьбы с переполнением буферов, и в то же время без их «голодания». В настоящее время BQL используется в NetDevices, которые поддерживают управление потоком. Анализ влияния размера очереди устройства на эффективность дисциплин массового обслуживания, проводимый с помощью моделирования ns‑3 и реальных экспериментов, приводится в:
    П. Импутато и С. Аваллоне. «Анализ влияния буферов сетевых устройств на планировщики пакетов с помощью эксперимента и симуляции». Практика и теория имитационного моделирования, 80 (Приложение C): 1–18, январь 2018 года. DOI: 10.1016 / j.simpat.2017.09.008

    P. Imputato and S. Avallone. An analysis of the impact of network device buffers on packet schedulers through experiments and simulations. Simulation Modelling Practice and Theory, 80(Supplement C):1–18, January 2018. DOI: 10.1016/j.simpat.2017.09.008

6.4.1 Модели очередей доступные в ns-3


Для уровня управления трафиком существуют опции:


  • PFifoFastQueueDisc: максимальный размер по умолчанию — 1000 пакетов.
  • FifoQueueDisc: максимальный размер по умолчанию — 1000 пакетов.
  • RedQueueDisc: максимальный размер по умолчанию — 25 пакетов.
  • CoDelQueueDisc: максимальный размер по умолчанию составляет 1500 килобайт.
  • FqCoDelQueueDisc: максимальный размер по умолчанию — 10024 пакета.
  • PieQueueDisc: максимальный размер по умолчанию составляет 25 пакетов.
  • MqQueueDisc: эта дисциплина очереди не имеет ограничений по объему.
  • TbfQueueDisc: максимальный размер по умолчанию — 1000 пакетов.
    Если интерфейсу назначается IPv4 или IPv6-адрес, связанный с NetDevice, и если дисциплина очереди еще не была установлена, то по умолчанию, на NetDevice устанавливается дисциплина pfifo_fast.

На уровне устройств существуют очереди для конкретных устройств:


  • PointToPointNetDevice. Конфигурация по умолчанию (заданная помощником) состоит в установке очереди DropTail по умолчанию. размер (100 пакетов).
  • CsmaNetDevice. Конфигурация по умолчанию (заданная помощником) состоит в установке очереди DropTail размера по умолчанию (100 пакетов).
  • WiFiNetDevice: настройка по умолчанию — установит очередь DropTail с размером по умолчанию (100 пакетов) для non-QoS станций и четыре очереди DropTail с размером по умолчанию (100 пакетов) для станций QoS.
  • SimpleNetDevice: настройка по умолчанию — установка очереди DropTail c размером по умолчанию (100 пакетов).
  • LTENetDevice: организация очереди происходит на RLC уровне ( RLC UM буфер по умолчанию составляет 10 * 1024 байт, RLC AM не имеет ограничения буфера).
  • UanNetDevice: по умолчанию на MAC уровне имеет очередь из 10 пакетов.

6.4.2 Изменение настроек по умолчанию


  • Тип очереди, используемой NetDevice, обычно можно изменить с помощью помощника устройства:
    NodeContainer nodes;
    nodes.Create (2);
    PointToPointHelper p2p;
    p2p.SetQueue ("ns3::DropTailQueue", "MaxSize", StringValue ("50p"));
    NetDeviceContainer devices = p2p.Install (nodes);
  • Тип дисциплины очереди, установленной на NetDevice, можно изменить с помощью помощника управления трафиком:
    InternetStackHelper stack;
    stack.Install (nodes);
    TrafficControlHelper tch;
    tch.SetRootQueueDisc ("ns3::CoDelQueueDisc", "MaxSize", StringValue ("1000p"));
    tch.Install (devices);
  • Если BQL поддерживается устройством, то оно может быть включено через помощника управления трафиком:
    InternetStackHelper stack;
    stack.Install (nodes);
    TrafficControlHelper tch;
    tch.SetRootQueueDisc ("ns3::CoDelQueueDisc", "MaxSize", StringValue ("1000p"));
    tch.SetQueueLimits ("ns3::DynamicQueueLimits", "HoldTime", StringValue ("4ms"));
    tch.Install (devices);
Теги:
Хабы:
Всего голосов 3: ↑3 и ↓0 +3
Комментарии 0
Комментарии Комментировать

Публикации

Истории

Работа