главы 1,2
глава 3
глава 4
глава 5 Глава 6 Строим топологии
6.1 Построение топологии шинной сети
6.2 Модели, атрибуты и реальность
6.3 Построение топологии беспроводной сети
6.4 Очереди в ns-3
6.4.1 Модели очередей доступные в ns-3
6.4.2 Изменение настроек по умолчанию В этом разделе мы собираемся расширить наши знания по сетевым устройствам и каналам 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. Одной вещью, которая может быть удивительно полезной, является небольшой ASCII рисунок, которое показывает схему топологии сети, которая строится в примере. Вы найдете похожий «рисунок» в большинстве наших примеров. В этом случае вы можете видеть, что мы собираемся расширить наш двухточечный пример (связь между узлами n0 и n1 ниже), прицепив шинную сеть с правой стороны. Обратите внимание, что это топология сети по умолчанию, вы можете варьировать количество узлов, создаваемых в локальной сети. Если вы установите nCsma в единицу, в локальной сети (канал CSMA) будет всего два узла — один обязательный узел и один «дополнительный» узел. По умолчанию есть три «дополнительных» узла, как показано ниже: Затем используется пространство имен ns‑3 и определяется компонент журналирования. Все так же, как это было в first.cc, поэтому пока ничего нового. Основная программа начинается немного по-другому. Мы используем флаг verbose для подробного вывода, чтобы знать наверняка включены ли компоненты журналирования в UdpEchoClientApplication и UdpEchoServerApplication. Этот флаг по умолчанию имеет значение true (компоненты журналирования включены), но позволяет отключить журналирование во время регрессионного тестирования этого примера. Мы видим знакомый подход, который позволит вам изменять количество устройств в сети CSMA через аргумент командной строки. Мы делали нечто похожее в разделе об аргументах командной строки 5.2.2, когда управляли количеством отправленных пакетов. Последняя строка гарантирует, что у вас будет хотя бы один «лишний» узел.
Код состоит из варианта ранее описанного API, поэтому вам он должен быть понятен. На следующем шаге создаются два узла, которые мы будем связывать через соединение точка-точка. Контейнер NodeContainer используется так же, как это было сделано в first.cc. Затем мы объявляем еще один NodeContainer для хранения узлов, которые будут частью шинной сети (CSMA). Сначала мы просто создаем экземпляр самого объекта-контейнера. Следующая строка кода получает первый узел (например, имеющий индекс один) из контейнера двухточечного узла и добавляет его в контейнер узлов, которые станут CSMA устройствами. Рассматриваемый узел в конечном итоге станет одновременно устройством точка-точка и CSMA устройством. Затем мы создаем несколько «дополнительных» узлов, которые образуют оставшуюся часть CSMA сети. Так как у нас уже есть один узел в сети CSMA — тот, что будет выступать как устройство точка-точка и CSMA устройство, количество «лишних» узлов определяется как желаемое число узлов сегменте CSMA минус один. Следующий фрагмент кода должен быть уже знаком. Мы создаем экземпляр PointToPointHelper и устанавливаем связанные атрибуты по умолчанию так, чтобы на устройствах, созданных с помощью помощника получить передачу со скоростью пять мегабит в секунду и задержкой две миллисекунды в канале. Затем мы создаем экземпляр NetDeviceContainer для отслеживания сетевых устройств «точка-точка» и устанавливаем устройства на узлах точка-точка. Выше мы упоминали, что в следующих строках появится помощник для CSMA устройств и каналов. CsmaHelper работает так же, как PointToPointHelper, но он создает и подключает CSMA устройства и каналы. Обратите внимание, что в случае CSMA для пары устройство — канал, скорость передачи данных указана атрибутом channelAttribute вместо deviceAttribute. Это потому, что настоящая сеть CSMA не позволяет смешивать, устройства 10Base-T и 100Base-T в одном канале. Сначала мы устанавливаем скорость передачи данных до 100 мегабит в секунду, и затем задержку в 6560 наносекунд на распространение по каналу со скоростью света (выбрана произвольно как 1 наносекунда на фут, соответствует отрезку кабеля длиной 100 метров). Обратите внимание, что вы можете установить атрибут, используя его собственный тип данных. Так же, как мы создали NetDeviceContainer для хранения устройств, созданных PointToPointHelper, мы создаем NetDeviceContainer для хранения устройств, созданных нашим CsmaHelper. Мы вызываем метод Install CsmaHelper для установки устройств в узлы csmaNodes NodeContainer. Теперь у нас есть созданные узлы, устройства и каналы, но у нас нет стеков протоколов. Как в first.cc скрипте, мы будем использовать InternetStackHelper для установки этих стеков. Напомним, что мы взяли один из узлов контейнера p2pNodes и добавили его в контейнер csmaNodes. таким образом чтобы охватить все узлы симуляции, нам нужно только установить стеки на оставшийся узел p2pNodes и узлы в контейнере csmaNodes. Как и в примере сценария first.cc, для назначения IP-адресов интерфейсов наших устройств мы будем использовать Ipv4AddressHelper. Сначала мы используем сеть 10.1.1.0для создания двух адресов, необходимых для соединения наших устройств точка-точка. Напомним, что мы сохраняем созданные интерфейсы в контейнере, чтобы впоследствии было проще извлекать адресную информацию для использования в настройке приложений. Теперь нам нужно назначить IP-адреса интерфейсам нашего CSMA устройства. Операция работает так же, как и для случая точка-точка, за исключением того, что мы сейчас выполняем операцию над контейнером с переменным числом CSMA устройств — помните, что мы сделали количество CSMA устройств управляемым от аргумента командной строки. Устройства CSMA в этом случае будут привязаны к IP-адресам сети10.1.2.0, как показано ниже. Теперь у нас построена топология, но нам нужны приложения. Этот раздел будет в основном похож на раздел приложений файла first.cc, но мы собираемся создать экземпляр сервера на одном из узлов с CSMA устройством и клиент на узле, имеющем только двухточечное устройство. Сначала мы настроим эхо-сервер. Мы создаем UdpEchoServerHelper и предоставляем конструктору требуемое значение атрибута, который является номером порта сервера. Напомним, что этот порт, при желании, можно изменить позже, используя метод SetAttribute, но сейчас нам требуется подставить в конструктор конкретное значение. Напомним, что контейнер csmaNodes содержит один из узлов, созданных для двухточечной сети, и nCsma «дополнительных» узлов. Предположим, мы хотим получить последний из «дополнительных» узлов. Нулевая запись в контейнере csmaNodes будет точка-точка. Самый простой способ это понять, так это представить, что если мы создадим один «дополнительный» CSMA узел, тогда в контейнере csmaNodes он окажется под индексом 1. Тогда, по математической индукции, если мы создадим nCsma «дополнительных» узлов, то последний узел будет с индексом nCsma. Вы это и видите в первой строке кода в Get. Клиентское приложение настроено также, как мы это делали в примере скрипта first.cc. Опять же, мы передаем необходимые атрибуты в конструктор UdpEchoClientHelper (в данном случае это удаленный адрес и порт). Мы говорим клиенту отправлять пакеты на сервер, который мы только что установили на последнем «дополнительном» CSMA узле. Мы устанавливаем клиент на самом левом двухточечном узле, показанном на иллюстрации топологии. Поскольку мы фактически соединили здесь две разные сети, нам нужна некоторая форма межсетевой маршрутизации. Ns‑3, чтобы помочь вам, предоставляет вам то, что мы называем глобальной маршрутизацией. Глобальная маршрутизация использует тот факт, что вся внутренняя сеть доступна в симуляции и проходит через все узлы, созданные для симуляции — она выполняет тяжелую работу по настройке маршрутизация для вас без необходимости настройки маршрутизаторов. По сути, каждый узел ведет себя так, как если бы он был маршрутизатором OSPF1, который за кулисами обменивается данными со всеми другими роутерами мгновенно и волшебно. Каждый узел генерирует объявления о состоянии канала и передает их непосредственно к глобальному диспетчеру маршрутов, который использует эту глобальную информацию для построения таблиц маршрутизации для каждого узла. Настройка этой формы маршрутизации выполняется одно строкой: Далее мы включаем трассировку pcap. Первая строка кода для включения трассировки pcap в двухточечном помощнике должна быть вам сейчас знакома. Вторая строка включает трассировку pcap в помощнике CSMA, и есть дополнительный параметр, с которым мы еще не встречались. Сеть CSMA является многоточечной сетью. Это означает, что в общей среде передачи могут существовать несколько конечных точек (как раз наш случай). С каждой из этих конечных точек связано сетевое устройство. Есть две основных альтернативы сбору трассировочной информации в такой сети. Один из способов — создать файл трассировки для каждого сетевого устройства и хранить только пакеты, которые испускаются или получаются этим устройством. Другой способ — выбрать одно из устройств. и поместить его в неразборчивый режим (Promiscuous mode). Это единственное устройство затем «прослушивает» все пакеты в сети и сохраняет их в один pcap файл. Так работает, например, tcpdump. Последний параметр включает в CSMA помощнике захват пакетов в неразборчивом режиме. В этом примере мы собираемся выбрать в CSMA сети одно из устройств и попросить его выполнить неразборчивый захват пакетов сети, тем самым подражая тому, как сделает tcpdump. Чтобы получить трассировку на компьютере с Linux, вы могли бы сделать что-то вроде tcpdump -i eth0. В данном случае мы указываем устройство с помощью csmaDevices.Get(1), который выбирает первое устройство в контейнере. Установка конечного параметра в значение true разрешает неразборчивый захват. Последний раздел кода просто запускает и очищает симуляцию, как в примере first.cc. Чтобы запустить этот пример, скопируйте скрипт-пример second.cc в рабочую директорию и используйте waf для сборки, как это вы делали с примером first.cc. Если вы находитесь в директории верхнего уровня репозитория, то просто наберите, Предупреждение: файл second.cc в качестве одного из наших регрессионных тестов, для проверки данного руководства. Т.е. исполняемый файл с именем second уже существует в проекте. Чтобы избежать путаницы, в показанном выше примере мы копируем файл second.cc с изменением имени на mysecond.cc. Если вы неукоснительно следовали руководству (не так ли), у вас все равно будет установлена переменная NS_LOG, так, что двигаемся вперед и очищаем эту переменную и запускаем программу. Так как мы в UDP эхо-приложениях настроили журналирование, также как мы делали в first.cc, когда вы запустите скрипт, вы увидите похожий вывод. » от UDP эхо-клиента, отправляющего пакет серверу. В этом случае сервер находится в другой сети (10.1.2.0). Второе сообщение «Received 1024 bytes from 10.1.1.1
» от UDP эхо-сервера, генерируемое при получении эхо-пакета. Финальное сообщение «Received 1024 bytes from 10.1.2.4» от эхо-клиента, указывающее, что он получило свое эхо от сервера обратно. Если вы сейчас зайдете в директорию верхнего уровня, вы найдете три файла трассировки: Давайте взглянем на именование этих файлов. Для всех оно имеет одинаковую форму,<Имя> - <узел> - <устройство> .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. Вы должны увидеть содержимое файла pcap: Первая строка дампа ожидаемо указывает, что тип связи — PPP (точка-точка)3. Затем вы видите эхо-пакет, покидающий узел 0 и через устройство, связанное с IP-адресом
10.1.1.1, направляется на IP-адрес 10.1.2.4 (самый правый CSMA узел). Этот пакет будет перемещаться по каналу «точка-точка» и приниматься устройством сети «точка-точка» на первом узле. Давайте взглянем:
$ tcpdump -nn -tt -r second-1-0.pcap
Теперь вы должны увидеть вывод pcap трассировки на другой стороне двухточечного линка: Здесь мы видим, что тип линка также PPP, как и следовало ожидать. Вы видите пакет с IP-адреса 10.1.1.1 (который был отправлено в 2.000000 секунд) в направлении IP-адреса 10.1.2.4 на этом интерфейсе. Теперь внутри этого узла пакет будет переадресован на интерфейс CSMA, и мы должны увидеть, что он выскочил на это устройство, направляясь к его конечному пункту назначения. Вспомним, что мы выбрали узел 2 в качестве неразборчивого анализатора для CSMA сети, поэтому давайте взглянем на second-2-0.pcapи посмотрим пакет там. Теперь вы должны увидеть неразборчивый дамп устройства 0 на узле 2: Как видите, тип соединения теперь «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. Обратите внимание, что второй узел напрямую не участвует в этом обмене, но отслеживает сеть и сообщает обо всем трафике что видит. Этот обмен виден в следующих строках, Затем, устройство 1 узла 1 идет дальше и отправляет эхо-пакет на UDP эхо-сервер по IP-адресу 10.1.2.4. Сервер получает эхо-запрос и переворачивает пакет, пытаясь отправить его обратно источнику. Сервер знает, что этот адрес находится в другой сети, которую он может достичь через IP-адрес 10.1.2.1. Это ему известно потому, что мы инициализировали глобальную маршрутизацию, и она выяснила все это для нас. Но узел эхо-сервера не знает MAC-адрес первого CSMA узла, поэтому он должен выполнить ARP запрос, как и первый CSMA узел. Затем сервер отправляет эхо-сигнал обратно на узел пересылки. Оглядываясь назад, на самый правый узел двухточечного линка, в последней строке дампа трассировки вы можете видеть отраженный пакет, возвращаемый по двухточечному линку. Наконец, вы можете снова взглянуть на узел, который вызвал эхо и увидеть, что отраженный пакет возвращается обратно к источнику за 2,017607 секунд, Напоследок напомним, что мы добавили возможность управления количеством CSMA устройств в симуляции с помощью аргумента командной строки. Вы можете изменить этот аргумент так же, как мы меняли количество пакетов в примере first.cc. Попробуйте запустить программу с четырьмя дополнительными устройствами: Теперь вы должны увидеть, Обратите внимание, что теперь эхо-сервер перенесен на последний из CSMA узлов, адрес которого 10.1.2.5 вместо случая по умолчанию, 10.1.2.4. Вполне возможно, что вы не будете удовлетворены файлом трассировки, созданным наблюдателем в сети CSMA. Если вас не интересует трафик с других устройств сети, вы можете получить трассировку с одного устройства. Это делается довольно легко.
Чтобы быть более конкретными, давайте посмотрим на scratch/mysecond.cc и добавим этот код. Помощники ns‑3 предоставляют методы, которые в качестве параметров принимают номер узла и номер устройства. Идем дальше и заменим вызовы EnablePcap вызовами ниже. Мы знаем, что хотим создать файл 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 может значительно облегчить определение номеров узлов в сложных топологиях. Давайте удалим старые файлы трассировки из директории верхнего уровня, чтобы избежать путаницы в том, что происходит, Если вы создадите новый скрипт и запустите симуляцию с аргументом
nCsma=100, вы увидите следующий вывод: Обратите внимание, что теперь эхо-сервер расположен по адресу 10.1.2.101
, что соответствует наличию 100 «дополнительных» узлов CSMA с эхо-сервером на последнем. Если вы запросите список файлов pcap в директории верхнего уровня, то увидите, Файл трассировки second-0-0.pcap относится к «самому левому» двухточечному устройству, которое является источником эхо-пакетов. Файл second-101-0.pcap соответствует крайнему правому устройству CSMA, в котором находится эхо-сервер. Вы возможно, заметили, что последний параметр вызова для включения трассировки pcap на узле эхо-сервера был false. Этот означает, что трассировка, собранная на этом узле, была в неразборчивом режиме. Чтобы проиллюстрировать разницу между неразборчивыми и разборчивыми трассировками, мы также попросили разборчивую трассировку для ближайшего к последнему узла. Продолжим и посмотрим на tcpdump для second-100-0.pcap. Теперь вы можете видеть, что узел 100 действительно является наблюдателем в эхо-обмене. Единственные пакеты, которые он получает, это ARP-запросы, которые передаются по всей CSMA сети. Теперь взгляните на tcpdump для second-101-0.pcap. Теперь вы можете видеть, что узел 101 действительно является участником эхо-обмена. Это удобный момент, чтобы сделать небольшое отступление и сделать важное замечание. Это может быть. а может и не быть очевидным для вас, но всякий раз, когда кто-то использует симуляцию, важно точно понимать, что моделируется, а что нет. Например, заманчиво думать об устройствах и каналах 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 предоставляет вам сверхгибкую базу для экспериментов. От вас зависит, что вы просите систему сделать, насколько создаваемые вами симуляции и результаты имеют связь с реальностью. В этом разделе, для расширения наших познаний в сетевых устройствах и каналах 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 и модуль мобильности, которые мы обсудим ниже. Иллюстрация топологии сети выглядит следующим образом: Вы можете видеть, что мы добавляем новое сетевое устройство к узлу с левой стороны двухточечного линка, который становится точкой доступа к беспроводной сети. Ряд беспроводных узлов STA создан для наполнения новой сети
10.1.3.0, как показано на левой стороне иллюстрации. После иллюстрации задействуется пространство имен ns‑3 и определяется компонент журналирования. Это все должно уже быть знакомо. Основная программа начинается так же, как second.cc, с добавления некоторых параметров командной строки для включения или отключения компонентов журналирования и для изменения количества создаваемых устройств. Как и во всех предыдущих примерах, следующим шагом является создание двух узлов, которые мы будем соединять линком точка-точка. Далее мы видим старого друга. Создается экземпляр PointToPointHelper и устанавливаются соответствующие атрибуты по умолчанию таким образом, чтобы на создаваемых помощником устройствах передатчики имели скорость пять мегабит в секунду, а у создаваемых каналов задержка была две миллисекунды. Затем мы устанавливаем устройства на узлы и канал между ними. Затем мы объявляем еще один NodeContainer для хранения узлов, которые будут частью шинной сети (CSMA). Следующая строка кода получает первый узел (например, имеющий индекс один) из контейнера двухточечного узла и добавляет его в контейнер узлов, которые получат устройства CSMA. Рассматриваемый узел будет содержать устройство точка-точка и CSMA устройство. Затем мы создаем несколько «дополнительных» узлов, которые образуют оставшуюся часть CSMA сети. Затем, мы создаем экземпляр CsmaHelper и устанавливаем его атрибуты, также как мы это делали в предыдущем примере. Мы создаем NetDeviceContainer для отслеживания созданных сетевых CSMA устройств, а затем инсталлируем CSMA устройства на выбранные узлы. Далее мы собираемся создать узлы, которые будут частью сети Wi-Fi. Мы создадим то количество узлов «станций», какое указано в аргументе командной строки, и мы будем использовать «самый левый» узел двухточечного линка как узел для точки доступа. Следующий фрагмент кода создает Wi-Fi устройства и канал связи Wi-Fi между этими узлами. Сначала мы настраиваем помощников PHY и канала: Для простоты, этот код для PHY-уровня и модели канала использует конфигурирование по умолчанию, с помощью методов
YansWifiChannelHelper::Default и YansWifiPhyHelper::Default, которые описаны в документации Doxygen API. Как только эти объекты будут созданы, мы создаем объект канала и связываем его с нашим менеджером объектов PHY уровня, гарантируя тем самым, что все объекты PHY уровня, созданные YansWifiPhyHelper используют один и тот же базовый канал, а значит и общую беспроводную среду, где они могут коммуницировать и интерферировать: Как только PHY помощник настроен, мы можем сосредоточиться на MAC уровне. Здесь мы решили работать с non-Qos MAC. Для установки параметров MAC используется объект WifiMacHelper. Метод SetRemoteStationManager сообщает помощнику тип используемого алгоритма управления скоростью. Он просит помощника использовать алгоритм AARF (Adaptive AutoRate Fallback) — подробности, конечно, доступны в Doxygen. Затем мы настраиваем тип MAC, SSID (Service Set Identification)сети, которую мы хотим настроить, и отключаем активное зондирование: Этот код сначала создает объект идентификатора набора служб (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 этих станций: Мы настроили Wi-Fi для всех наших STA узлов, и теперь нам нужно настроить AP узел (точку доступа). Чтобы отразить требования AP, мы начнем этот процесс, с изменения атрибутов по умолчанию для WifiMacHelper. В этом случае WifiMacHelper будет создавать MAC уровень
«ns3::ApWifiMac», причем последний указывает, что должен быть создан экземпляр MAC, настроенный как AP. Мы не меняем настройки по умолчанию у атрибута «QosSupported», поэтому он остается false — отключение поддержки QoS на созданных точках доступа в стиле 802.11e/WMM. Следующие строки создают одну точку доступа, которая использует тот же набор атрибутов PHY уровня (и канал), что и для станций: Теперь мы добавим модель мобильности. Мы хотим, чтобы STA узлы были подвижными и бродили внутри ограничивающего поля, а узел AP мы хотим сделать стационарным. Чтобы облегчить работу, мы используем MobilityHelper. Сначала создаем экземпляр объекта MobilityHelper и устанавливаем некоторые атрибуты, управляющие функциональностью «распределителя положений». Этот код указывает помощнику мобильности использовать для первоначального размещения STA узлов двумерную сетку. Не стесняйтесь исследовать Doxygen для класса ns3::GridPositionAllocator, чтобы точно понять, что происходит. Мы разместили наши узлы на начальной сетке, но теперь нам нужно рассказать им, как двигаться. Мы выбираем модель RandomWalk2dMobilityModel, в которой узлы перемещаются в случайном направлении со случайной скоростью внутри ограничительной рамки. Теперь мы говорим MobilityHelper установить модель мобильности на STA узлах. Мы хотим, чтобы точка доступа во время симуляции оставалась в фиксированном положении. Мы получаем это, устанавливая для её узла модель мобильности  Теперь у нас есть созданные узлы, устройства, каналы и модели мобильности, выбранные для узлов Wi-Fi. Но у нас отсутствуют стеки протоколов. Как и ранее, для их установки мы воспользуемся InternetStackHelper. Как и в примере сценария second.cc, мы будем использовать Ipv4AddressHelper для назначения IP-адресов интерфейсов наших устройств. Сначала мы используем сеть
10.1.1.0 для создания двух адресов, необходимых для соединения наших устройства точка-точка. Затем мы используем сеть 10.1.2.0 для назначения адресов CSMA сети, а затем мы назначаем адреса из сети 10.1.3.0 для STA устройств и точки доступа в беспроводной сети. Мы помещаем эхо-сервер в «самый правый» узел на иллюстрации в начале файла. Мы делали так ранее. И мы помещаем эхо-клиент на последний созданный нами STA узел, нацеливая его на сервер в CSMA сети. Мы уже видели подобные действия раньше. Поскольку мы построили здесь объединение сетей, то нам нужно включить межсетевую маршрутизацию, как мы это делали в примере сценария second.cc. Некоторых пользователей может удивить то, что созданная нами симуляция никогда не остановится «естественным образом». Этот потому, что мы попросили беспроводную точку доступа генерировать биконы ( beacon пакеты). Она будет генерировать биконы постоянно, и это приведет к тому, что в симуляторе будут непрерывно планироваться новые события. Поэтому мы должны сказать симулятору остановиться, даже если им могут быть запланированы события для генерации очередного бикона. Следующая строка кода говорит симулятору остановиться, чтобы бы мы не симулировали биконы в бесконечном цикле. Мы создаем трассировку, достаточную для охвата всех трех сетей: Эти три строки кода начнут трассировку pcap на обоих точечных узлах, которые служат нашей магистралью, запустят случайную трассировку (мониторинг) в Wi-Fi и в CSMA сетях. Это позволит нам увидеть весь трафик с минимальным количеством файлов трассировки.
Наконец, мы на самом деле запускаем симуляцию, очищаем и затем выходим из программы. Для запуска этого примера необходимо скопировать пример сценария third.cc в рабочую директорию и использовать для сборки Waf, как мы это делали с примером second.cc. Если вы находитесь в директории верхнего уровня репозитория, то напечатайте, Опять же, поскольку мы настроили UDP эхо-приложения так же, как и в сценарии second.cc, вы увидите похожий вывод. Напомним, что первое сообщение «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» соответствует устройству «точка-точка» на нулевом узле — левой стороне опорной сети («backborn»). Файл «third-1-0.pcap» соответствует устройству точка-точка на первом узле — правой стороне опорной сети сети. Файл «Third-0-1.pcap» — это неразборчивая трассировка (в режиме монитора) из сети Wi-Fi и файл «third-1-1.pcap» будет неразборчивая трассировка CSMA сети. Можете ли вы проверить это, инспектируя код?
Поскольку эхо-клиент находится в сети Wi-Fi, начнем с него. Давайте посмотрим на неразборчивую трассировку (режим монитора), которую мы захватили в этой сети. Вы должны увидеть wifi-подобное содержимое, которое вы не видели здесь ранее: Теперь видно, что тип связи теперь 802.11, как и следовало ожидать. Вы уже сможете понять, что происходит в этой трассировке, и найти IP-пакеты эхо-запросов и ответов. Мы оставляем вам полный разбор дампа трассировки как упражнение. Теперь посмотрите на файл pcap для левой части линка «точка-точка», Опять же, вы должны увидеть отчасти знакомое содержимое: Это эхо-пакет, идущий слева направо (от Wi-Fi до CSMA) и обратно через линию «точка-точка». Теперь посмотрите на файл pcap с правой стороны линка «точка-точка», Опять же, вы должны увидеть знакомое содержимое: Это также эхо-пакет, идущий слева направо (от Wi-Fi до CSMA) и обратно через линк точка-точка с немного другими временами, чем вы могли ожидать.
Эхо-сервер находится в CSMA сети, давайте посмотрим на неразборчивую трассировку там: Вы должны увидеть знакомое содержимое: Оно должно быть понятным. Если вы забыли, то вернитесь и посмотрите обсуждение примера second.cc. Это та же последовательность. Поскольку мы потратили много времени на настройку моделей мобильности для беспроводной сети, было бы стыдно закончить не показав, как STA узлы фактически перемещаются во время симуляции. Давайте сделаем это, подключив источник трассировки изменения курса в MobilityModel. Для этого просто нужно заглянуть в следующую главу 7, но тем не менее хороший момент, чтобы привести пример именно сейчас. Как упоминалось в главе 5, система трассировки ns‑3 разделена на источники трассировки и приемники трассировки, и мы предоставляем функции для их соединения. Для инициации событий трассировки мы будем использовать дефолтный источник трассировки изменений модели мобильности. Нам нужно написать трассировщик для подключения к этому источнику, который будет отображать информация для нас. Несмотря на сложное описание, все довольно просто. Прямо перед основной программой в сценарий scratch/mythird.cc (т.е. сразу после оператора
NS_LOG_COMPONENT_DEFINE), добавьте следующую функцию: Этот код просто извлекает информацию о положении из модели мобильности и записывает x и y положения узла. Мы организуем программу таким образом, чтобы эта функция вызывалась каждый раз, когда беспроводной узел с эхо-клиентом меняет свою позицию. Мы сделаем это с помощью функции Config::Connect. Добавьте в скрипт следующие строки кода перед вызовом Simulator::Run. Здесь мы создаем строку, содержащую путь трассировки пространства имен события, к которому мы хотим подключиться. Во-первых, используя как описано ранее метод GetId, мы должны выяснить, какой узел нам нужен. Если использовано число CSMA и беспроводных узлов заданное по умолчанию, это будет седьмой узел и путь пространства имен трассировки к модели мобильности будет выглядеть,
/NodeList/7/$ns3::MobilityModel/CourseChange. Основываясь на обсуждении в разделе трассировки, вы можете сделать вывод, что этот путь трассировки ссылается на седьмой узел в глобальном NodeList. Он определяет то, что называется агрегированным объектом типа ns3::MobilityModel. Префикс в виде знака доллара подразумевает, что MobilityModel агрегируется на седьмом узле. Последний элемент пути означает, что мы подключились к событию «CourseChange» этой модели. Мы устанавливаем связь между источником трассировки в узле 7 и нашим приемником трассировки, вызывая Config::Connect и предавая путь пространства имен. Как только это будет сделано, каждое событие изменения курса на седьмом узле будет подключено к нашему приемнику трассировки, который в свою очередь распечатает новую позицию. Если вы сейчас запустите симуляцию, вы увидите изменения курса, отображаемые по мере их появления. Выбор дисциплин очередей в 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): Для уровня управления трафиком существуют опции: На уровне устройств существуют очереди для конкретных устройств: Разработчик ПО для радиосвязи