Хабрахабр

LLTR Часть 1: Первые шаги в OMNeT++ и INET

Попросту говоря это “симулятор дискретных событий”, включающий: IDE для создания моделей, и сам симулятор (GUI). OMNeT++ (Objective Modular Network Testbed in C++) Discrete Event Simulator – это модульная, компонентно‑ориентированная C++ библиотека и фреймворк для дискретно‑событийного моделирования, используемая прежде всего для создания симуляторов сетей.

INET Framework – “библиотека” сетевых моделей для OMNeT++.

КДПВ: LLTR Часть 1 – OMNeT++ 5 the Open Simulator :: LLTR Model :: for freedom use

7 MiB)
Полная версия GIF (15.

В предыдущих частях…

Автоматическое определение топологии сети и неуправляемые коммутаторы.
0. (+ classic Habrahabr UserCSS) Миссия невыполнима?

В этой части:

  • создадим “свой первый” протокол (на примере LLTR Basic);
  • выберем подходящий симулятор сити для отладки протокола (и создания его модели);
  • познаем тонкости настройки окружения для симулятора и его IDE (конфигурирование, компиляция, линковка, тюнинг, патчинг, игнорирование устаревшей документации; и другие англицизмы в большом количестве);
  • столкнемся со всем, с чем можно столкнуться, при создании своей первой модели своего первого протокола в не своем незнакомом симуляторе сети;
  • пройдем весь путь вместе:
    • от счастья, принесенного успешной (наконец!) компиляции первого проекта с пустой сетью,
    • до полного погружения в эксперименты с функционирующей моделью протокола;
  • tutorial, все описано в виде tutorial – мы будем учиться на ошибках – будем совершать их, и будем понимать их (природу), дабы элегантно/эффективно с ними справится;
  • репозиторий (git ), в коммитах и тегах которого сохранены все шаги (“Add …”, “Fix …”, “Fix …”, “Modify …”, “Correct …”, …), от начала и до конца.

Note: дополнительная информация для читателей хаба “Mesh-сети”.

Note: [про используемую структуру разделов] структура разделов tutorial/how‑to обычно отличается от структуры разделов в справочнике: в справочнике – структура разделов позволяет за минимальное количество шагов дойти до искомой информации (сбалансированное дерево); в tutorial/how‑to, где разделы сильно связаны логически, а отдельный раздел, по сути, является одним из шагов в последовательности шагов, структура представляет собой иерархию закладок (якорей), которая позволяет в любом месте tutorial/how‑to напомнить (сослаться) о фрагменте описанном ранее.

off‑topic: про html5 тег <section> и теги заголовков <h#>

Структуру текста теперь можно было явно отразить во вложенности (иерархии) тегов. Как хорошо, что в HTML5 появился тег <section>, с его помощью стало возможным напрямую задавать уровень вложенности раздела (при помощи манипуляции вложенностью тегов <section> друг в друга).

теперь вложенность разделов определяется вложенностью тега <section>, то для указания названия раздела – достаточно было использовать всего лишь один тег <h1> в виде: “<section><h1>название раздела</h1>текст раздела</section>”.
Это повлияло и на теги заголовков <h#>, т.к.

Я этим пользовался уже давно (с самого появления <section>), но создавая эту статью, увидел еще одно достоинство использования <section>.

То есть, такой раздел должен вначале притворится “рутинным”, а в середине создать “wow/wtf‑эффект”.
Хорошее название раздела должно точно отражать его суть, однако бывают случаи, когда нужно придержать (не раскрывать) суть до середины раздела. Представьте книгу (детектив), на обложке которой будет вся информация о “убийце”. Логически это все – один раздел, но если раскрыть его название в самом начале раздела, то само название будет являться спойлером.

Он позволяет определить название раздела в любом месте внутри себя, т.е.
Здесь “на сцену выходит” тег <section>. Пример: “<section>текст раздела<h1>название раздела</h1>продолжение текста раздела</section>”. не обязательно в самом начале. Можно даже сделать так, чтобы название раздела визуально появлялось в его начале, после того как читатель дойдет до определенного момента (до тега <h1> в html). Получается, мы можем одновременно сохранить логическую структуру текста, и показать название раздела в нужный момент.

Вот только более чем за 9 лет существования <section>, браузеры так и не научились правильно строить “HTML5 document outline” для обеспечения доступности.

В документе со сложной структурой трудно* определить, начиная с какого тега (section, article, …) следует начать нумерацию заголовков (h1, h2, h3, …).
Почему не научились? А если на одной странице не один документ, а несколько? А теперь представьте, что сам документ размещен на странице подобной этой (с множеством дополнительных блоков, не имеющих отношение к самому документу, но имеющих заголовки), причем везде для заголовков используется h1. Тем не менее, визуально все выглядит хорошо (пример документа).

ниже).
* – на самом деле это не трудно, в стандарте все описано, но в реальности это не работает (объяснение см.

Здесь, благодаря стилям, появилась дополнительная информация – соответствие между иерархией section и уровнями заголовков (h#).
Почему визуально все выглядит хорошо? Для этого потребуется добавить в CSS дополнительное свойство для элемента заголовка, указывающее его уровень, например: Так может при построении “HTML5 document outline” следует воспользоваться информацией из CSS?

body>section>h2 { heading-level: 1; font-size: 1.8em; }
body>section>section>h2 { heading-level: 2; font-size: 1.4em; }
body>section>section>section>h2 { heading-level: 3; font-size: 1.17em; }
body>section>section>section>section>h2 { heading-level: 4; font-size: 1em; }
body>section>section>section>section>section>h2 { heading-level: 5; font-size: 0.83em; }

В этом случае уровень заголовка задает сама секция:
Либо более строгий вариант – в одной секции допускается использовать только один заголовок.

body>section { heading-level: 1; }
body>section>section { heading-level: 2; }
body>section>section>section { heading-level: 3; }
body>section>section>section>section { heading-level: 4; }
body>section>section>section>section>section { heading-level: 5; }

, и неважно, какой в итоге будет использоваться тег заголовка: h1 или h5.

Может можно ограничиться только разметкой (HTML)?
Однако, если раньше для создания “heading-level outline” достаточно было иметь только разметку (HTML), то теперь нужны еще и стили (CSS). Так вот, проблема не в самом алгоритме, а в том, что в качестве “sectioning root” элемента может выступать только ограниченный (фиксированный) набор тегов. Этим вопросом мы вплотную подошли к проблеме алгоритма построения “heading-level outline”, описанного в стандарте. Раньше им достаточно было для этого использовать несколько тегов h1 на одной странице (и они это делали). Но у людей часто возникают “нестандартные желания”: “я хочу, чтобы на моей странице со списком статей тег article являлся ‘sectioning root’ элементом”, “а я хочу, чтобы произвольная секция стала ‘sectioning root’ элементом”. Так может сделать так, чтобы любая секция (теги: section, article, …) становилась “sectioning root” элементом, если заголовок в ней задан при помощи тега h1?..

# Первые шаги: “перед моделированием” / “мозговой штурм”

Листочек

НЛОприлетелоиоставилоэтотпробелздесь? Обратная сторона листочка из предыдущей статьи.

# Детализация протокола

На примере LLTR Basic.
В начале определим, что нам нужно включить в протокол.

Итераций в LLTR много ( >1), поэтому первое, что нужно включить в протокол – управление запуском и остановкой каждой итерации.
Основа LLTR – это итерации сбора статистики на множестве хостов во время сканирования сети. То есть синхронизировать все хосты. Если учесть, что хостов тоже много ( >1), то управление будет заключаться в том, чтобы определенным способом сообщать всем хостам время начала итерации и время окончания итерации.

То есть в каждой итерации один из хостов должен “осознавать” себя unicast src хостом, цель которого посылать трафик на unicast dst хост.
В каждой итерации есть свой unicast src хост и unicast dst хост, поэтому следующее, что нужно включить – способ назначения для каждой итерации unicast src и dst.

По завершению всех итераций, всю собранную статистику со всех хостов нужно отправить на один хост для обработки.
И последнее. Этот хост проанализирует собранную статистику, и построит топологию сети.

Например, мы хотим, чтобы программа, использующая LLTR, смогла работать без root прав, и из пространства пользователя (т.е.
Также, на этом шаге, можно подумать про некоторые детали реализации (ограничения) протокола. без установки в систему специального драйвера), значит, LLTR должен работать, например, поверх TCP и UDP.

То есть, конечно, можно сразу же продумать все до мелочей, но при этом есть риск “скатится в локальный оптимум”, и не заметить “более лучший” вариант реализации.
Все остальные делали реализации, определятся сами, в процессе создания модели. Вспоминая генетический алгоритм ;). Хорошо, когда моделей будет несколько – если для каждого варианта реализации будет своя модель, то появится возможность комбинировать модели, и шаг за шагом приходить к лучшей реализации. Например, в одной реализации/модели может быть централизованное управление, в другой – децентрализованное, в третей – комбинация лучших частей из предыдущих двух вариантов.

# Выбор симулятора сети

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

Не все симуляторы позволяют легко это сделать.
В основном, от симулятора сети нам нужна возможность реализации “своего” протокола.

Скорее всего, эмуляторы создадут множество ограничений, которые будут только мешать в ходе экспериментов.
А вот присутствие эмуляторов ОС реального сетевого оборудования “мировых брендов”, наоборот – не нужно.

С выбором симулятора мне помогла статья Evaluating Network Simulation Tools (наши требования к симулятору во многом совпадали) и OMNeT++ General 'Network' Simulation.

# Установка OMNeT++ и INET

0. Загружаем OMNeT++ 5.

Качаем INET 3.
И так как OMNeT++ – это всего лишь “симулятор дискретных событий”, то понадобится еще и INET – библиотека сетевых моделей (протоколы и устройства). 0. 4. На самом деле его можно было установить из IDE, но я рекомендую поставить вручную (позже будет ясно почему).

Продолжу на примере Windows.
Установка в *nix и в Windows мало чем отличается.

0\INSTALL.txt).
Распаковываем OMNeT++ в %ProgramData% (C:\ProgramData\), и открываем файл INSTALL.txt (C:\ProgramData\omnetpp-5. В нем сказано, что подробная инструкция находится в “doc/InstallGuide.pdf”, дальше написано, что если не хотите ее читать, то просто выполните:

setenv
$ ./configure
$ make $.

Но не спешите это делать!

setenv”.
Во‑первых, обратите внимание на первую команду “. 0” нет файла “setenv” (в версии 5. В директории “omnetpp-5. Он и не нужен (для Windows), поэтому просто запускаем “mingwenv.bat” (советую перед запуском посмотреть, что он делает… во избежание внезапного rm ). 0b1 он был). По окончании отколется терминал (mintty).

Во‑вторых, советую немного подправить файл “configure.user” (если упомянутый параметр закомментирован в файле, то его нужно раскомментировать):

  • Если хотите использовать Clang (по умолчанию), то оставьте
    PREFER_CLANG=yes
    и настройте:
    • CFLAGS_RELEASE (опции компилятора):
      CFLAGS_RELEASE='-O2 -march=native -DNDEBUG=1'
  • Если хотите использовать GCC вместо Clang (а вы, скорее всего, захотите использовать именно GCC, увидев, что написано в 398 строчке файла “configure.in”), то установите
    PREFER_CLANG=no
    и настройте:
    • CFLAGS_RELEASE (опции компилятора). Можно выбрать или
      CFLAGS_RELEASE='-O2 -mfpmath=sse,387 -ffast-math -fpredictive-commoning -ftree-vectorize -march=native -freorder-blocks-and-partition -pipe -DNDEBUG=1'
      или
      CFLAGS_RELEASE='-O2 -fpredictive-commoning -march=native -freorder-blocks-and-partition -pipe -DNDEBUG=1'
      или
      CFLAGS_RELEASE='-O2 -march=native -freorder-blocks-and-partition -pipe -DNDEBUG=1'
      (расположено в порядке уменьшения вероятности возникновения глюков).
    • Также стоит добавить CXXFLAGS в виде '-std=c++11 '+CFLAGS_RELEASE. Например:
      CXXFLAGS='-std=c++11 -O2 -fpredictive-commoning -march=native -freorder-blocks-and-partition -pipe -DNDEBUG=1'
    • JAVA_CFLAGS (просто раскомментируем):
      JAVA_CFLAGS=-fno-strict-aliasing
  • PREFER_QTENV=yes
  • Отключаем 3D визуализацию:
    WITH_OSG=no
    Она конечно красивая, но нам не понадобится.
  • Параллельное (на множестве CPU) выполнение симуляции (WITH_PARSIM), к сожалению, тоже стоит отключить, однако без него компоновка (linker) завершается неудачей, поэтому оставим включенным:
    WITH_PARSIM=yes

Почему его стоит отключить?

Подробнее в разделе 16. Если его явно не использовать, то он не нужен (в теории). 3, и 16. 1, 16. 2 “Parallel Simulation Example” в “doc/InstallGuide.pdf”, или тут. 3.

Теперь в терминале (mintty) можно выполнить:

./configure && make clean MODE=release
make MODE=release –j17

5×ядер.
Note:17” следует заменить на количество ядер CPU + 1, либо на 1.

Предостережение для любознательных (сборка 64bit)

В директории “tools/win32” находится MSYS2 его пакеты компиляторов можно обновлять:

А OMNeT++ можно собрать под 64bit.

А для перехода на 64bit потребуется еще больше усилий.
Но OMNeT++ может просто не собраться более новой версией GCC (так было с первой бэткой пятой версии OMNeT++ – без правки исходников она нормально собиралась только с GCC 4.x). Затем, если пролистаете исходники OMNeT++, то увидите, что там часто используется тип long вместо int32_t, size_t и ptrdiff_t (а также uintptr_t и intptr_t). Для начала потребуется пересмотреть опции компиляции (fPIC, не нужен?). В *nix в 64bit (LP64) сборке размер long будет 64bit, а в Windows (LLP64) – 32bit (см. Чем это грозит? Придется заменять long на size_t и ptrdiff_t, но и здесь вас будут поджидать “подводные камни”. модели данных). Поэтому часть long переменных нужно будет оставить 32bit, а другую часть сделать 64bit. Например, можно открыть “src/utils/opp_lcg32_seedtool.cc”, и взглянуть на строку 231 – index либо можно оставить 32bit (заменить на int32_t), либо сделать 64bit и модифицировать все битовые_маски+описания+(возможно)немного_логики. В общем, для корректной работы, нужно проделать все пункты из:

Причем то же самое надо проделать и с многочисленными библиотеками для OMNeT++, например, с INET.

В общем, предостерегаю от попыток сделать 64bit сборку OMNeT++.

0 и меньше).
Под *nix я также рекомендую использовать 32bit сборку (по крайне мере с версией 5.

Возможно, когда‑нибудь Andrey2008 возьмется проверить код OMNeT++ и INET… А пока предлагаю просто найти и просмотреть все “FIXME”/“Fix” в коде ;).

S.
P. 4. упоминания о том, что код OMNeT++ проверяли статическим анализатором кода – отсутствуют, а вот в файлах “ChangeLog” INET 3. 0 можно найти 70 упоминаний про устранение дефектов после сканирования в Coverity.

Для удобства можно создать ярлык на IDE “%ProgramData%\omnetpp-5.
OMNeT++ использует Eclipse в качестве IDE. В директории “ide/jre/” находится JRE v1. 0\ide\omnetpp.exe”, и расположить его в легкодоступном месте. 0_66-b18. 8. Если в системе уже установлен совместимый JRE/JDK, то директорию “ide/jre/” можно спокойно удалить, заменив символьной ссылкой на местоположение системного JRE.

Главное, чтобы в пути к новой директории использовались только латинские буквы (+ символы), и не было пробелов.
При первом запуске Eclipse предлагает поместить workspace в директорию “samples”, однако лучше расположить ее в любой другой удобной вам директории вне “%ProgramData%”.

После закрытия Welcome, IDE предложит установить INET (как было написано выше), и импортировать примеры – откажитесь от обоих пунктов.

Настройки Eclipse, опции JVM, дополнительные плагины и темы

Добавить в файл “ide/omnetpp.ini” (для правки подойдет любой редактор, понимающий LF перевод строки; notepad не подойдет), сохранив пустую последнюю строку: Опции JVM.

-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+AggressiveOpts
-XX:+TieredCompilation
-XX:CompileThreshold=100

Eclipse tuning (un[7z]me)

Чтобы сделать Eclipse, таким как на картинке – загляни внутрь картинки.

Директорию “inet” из скаченного ранее архива (inet-3.
Настало время установить INET. 0-src.tgz) нужно перенести в workspace. 4. Можно воспользоваться им (раздел “If you are using the IDE”), но только не собирайте (Build) проект! В директории есть файл “INSTALL” с пошаговым описанием установки.

Импортируем INET:

  1. В Eclipse открыть: File > Import.
  2. Выбрать: General / Existing Projects to the Workspace.
  3. В качестве “root directory” выбрать местоположение workspace.
  4. Удостоверьтесь, что опция “Copy projects into workspace” выключена.
  5. После нажатия на кнопку “Finish”, дождитесь окончания индексации проекта (% выполнения см. внизу, в строке статуса – “C/C++ Indexer”).

Настроим проект:

  • A. отключим ненужные для LLTR компоненты;
  • B. переключим сборку на релиз;
  • C. избавимся от глюков “OMNeT++ Make Builder” (opp_makemake) – раньше, при его выборе, часто происходила перегенерирация Makefile, даже когда этого не требовалось;
  • D. включим параллельную компиляцию;
  • E. включим оптимизации;
  • F. включим подсветку синтаксиса для c++11, в нескольких местах;
  • G. подправить баг связанный с “#include” (случается, если несколько раз менять “Current builder”; может случиться и в других случаях).

В файле “inet/.oppfeatures” есть строка “inet.examples.visualization” нужно добавить после нее пустую строку, в которой написать “inet.tutorials.visualization”, желательно сохранив отступ слева (по аналогии с другими параметрами “nedPackages” в файле).
Перед настройкой {A} надо подправить один из файлов проекта. Можно вначале сделать {A}, и посмотреть на ошибки, а затем подправить файл “inet/.oppfeatures” – при этом Eclipse предупредит о нарушении целостности в настройках, и предложит профиксить их (соглашаемся на это). Если это не сделать, то ничего страшного не случится, просто после настройки в “Problems” (Alt+Shift+Q,X) будут всегда висеть ошибки, связанные с “inet.tutorials.visualization”.

Приступим (панель “Project Explorer” >проект “inet” >контекстное меню >Properties):

  1. Раздел “OMNeT++” > подраздел “Project Features”
    1. {A} убираем все, кроме:
      • TCP Common
      • TCP (INET)
      • IPv4 protocol
      • UDP protocol
      • Ethernet
    2. кнопка “Apply”.
  2. Раздел “С/С++ Build”:
    1. кнопка “Manage Configurations…” > сделать активным “gcc-release” {B};
    2. выбрать конфигурацию “gcc-release [ Active ]” {B}.
    3. Подраздел “Tool Chain Editor”:
      1. в качестве “Current builder” выбрать “GNU Make Builder” для обеих конфигураций: “gcc-debug” и “gcc-release” {C}, внимание: если в будущем изменить “Current builder”, то все придется перенастраивать заново!
      2. кнопка “Apply”.
    4. Вкладка “Behavior” (вернутся в корень раздела “С/С++ Build”):
      1. установить “Use parallel jobs” равным N (в качестве N можно выбрать либо число ядер CPU + 1, либо 1.5×ядер) – это позволит использовать все ядра CPU для компиляции {D} (настраиваем для “gcc-debug” и “gcc-release”).
    5. Вкладка “Build Settings”:
      1. отключить “Use default build command”;
      2. строку “Build command” заменить на “make MODE=release CONFIGNAME=${ConfigName} -j17” (“17” заменить на предыдущее значение в строке, т.е. на выбранный N) {E}, то же самое можно сделать и для конфигурации “gcc-debug”, заменив в строке “MODE=release” на “MODE=debug”, после этого не забудь переключиться обратно на “gcc-release [ Active ]”.
    6. кнопка “Apply”.
  3. Раздел “С/С++ General”:
    1. Подраздел “Paths and Symbols”:
      1. Вкладка “Includes”:
        1. кнопка Add: добавить директорию “../src” с выбранными “Add to all configurations” и “Add to all languages” {G} – изначально “../src” есть в языке “GNU C++”, но, в неопределенный момент, он может стереться из списка;
        2. кнопка “Apply”, и проверь, что “../src” появилось во всех языках и конфигурациях.
      2. Вкладка “Symbols”:
        1. кнопка Add: добавить символ “__cplusplus” со значением “201103L” и выбранными “Add to all configurations” и “Add to all languages” – {F} подробнее;
        2. кнопка “Apply”, и проверь, что в конфигурации “gcc-debug” у “__cplusplus” значение “201103L”.
      3. Вкладка “Source Location”:
        1. Проверь, что в списке один пункт, и он указывает на “/inet/src{G}, если там что‑то другое (например, просто “/inet”), то удаляй то, что есть и добавь (“Add Folder…”) “/inet/src”. Затем кнопка “Apply”, и возвращение к {A}, т.к. все фильтры при удалении были стерты. Кстати, “/inet” на самом деле можно оставить – с ним тоже все нормально собирается, но лучше сузить до оригинального “/inet/src”.
    2. Подраздел “Preprocessor Include Paths, Marcos etc.” > вкладка “Providers”:
      1. Выбрать “CDT GCC Build-in Compiler Settings”:
        1. В группе “Language Settings Provider Options” нажать на ссылку “Workspace Settings”:
          1. вкладка “Discovery”: опять выбрать “CDT GCC Build-in Compiler Settings”, и добавить “-std=c++11 ” перед “${FLAGS}” в “Command to get compiler specs”, должно получится примерно так `${COMMAND} -std=c++11 ${FLAGS} -E -P -v -dD "${INPUTS}"` {F}, подробнее здесь и здесь;
          2. кнопка “Apply”, “Ok” (закрываем окно).
        2. переместить “CDT GCC Build-in Compiler Settings” выше “CDT Managed Build System Entries” (для обеих конфигураций: “gcc-release” и “gcc-debug”) {F}, подробнее – после этого мы потеряем возможность переопределять символы “CDT GCC Build-in Compiler Settings” через “CDT Managed Build System Entries” (“С/С++ General” >“Paths and Symbols” > “Symbols”), переопределить можно будет только через добавление значений в “CDT User Settings Entries” во вкладке “Entries” для каждого языка по отдельности (альтернатива: не меняем порядок, т.к. в “CDT Managed Build System Entries” уже исправили значение “__cplusplus”; не меняем порядок, удаляем все упоминания “__cplusplus” из “CDT Managed Build System Entries”, и следим, чтобы он там не появлялся в будущем);
        3. кнопка “Apply”, и проверить, что во вкладке “Entries” у языка “GNU C++” в “CDT GCC Build-in Compiler Settings” (чекбокс [в нижней части окна] “Show build-in values” должен быть включен) есть запись “__cplusplus=201103L” (она будет ближе к концу).
    3. Подраздел “Indexer”:
      1. в качестве “Build configuration for indexer” выбрать “gcc-release” {B};
      2. кнопка “Apply”.

Поясню.
Некоторые проблемы могут возникнуть с {E}. В таком случае Eclipse передаст нужные параметры в g++ через make. Если все нормально, то Eclipse должен подхватить те настройки, которые были заданы в “configure.user” перед конфигурированием OMNeT++ (./configure). Проверить можно, дописав в “Build command” {E}--just-print” или “--trace”, и, запустив сборку (панель “Project Explorer” >проект “inet” >контекстное меню >“Clean Project” и “Build Project”), открыть “Console” (Alt+Shift+Q,C), в нем должно выводится что‑то похожее на “g++ -c -std=c++11 -O2 -fpredictive-commoning -march=native -freorder-blocks-and-partition -pipe -DNDEBUG=1 …”. Однако не всегда все идет, как планировалось, и лучше проверить, что происходит в реальности. Если этого нет, то можно последовать совету из уже упомянутой статьи.

Либо подправить переменные окружения

Опять открываем настройки проекта (панель “Project Explorer” >проект “inet” >контекстное меню >Properties):

  1. Раздел “С/С++ Build”:
    1. Подраздел “Build Variables” (проверь, что текущая конфигурация “gcc-release [ Active ]”):
      1. кнопка “Add…”, имя “CFLAGS”, тип “String”, значение “-O2 -fpredictive-commoning -march=native -freorder-blocks-and-partition -pipe”;
      2. кнопка “Add…”, имя “CXXFLAGS”, тип “String”, значение “-std=c++11 -O2 -fpredictive-commoning -march=native -freorder-blocks-and-partition -pipe”;
      3. кнопка “Apply”.
    2. Подраздел “Environment”:
      1. кнопка “Add…”, имя “CFLAGS”, значение “${CFLAGS}”;
      2. кнопка “Add…”, имя “CXXFLAGS”, значение “${CXXFLAGS}”;
      3. кнопка “Apply”.

В Process Explorer также можно посмотреть, во что раскрывается “-march=native” при передаче в “cc1plus.exe”.
Кстати, при некоторой сноровке, параметры запуска g++ можно было посмотреть, не используя флаги “--just-print” и “--trace”, а используя Process Explorer.

Проверьте, что сейчас активна конфигурация “gcc-release” {B}, и если добавляли ранее флаги “--just-print” или “--trace” для проверки {E}, то их нужно убрать.
Теперь, наконец, можно собрать INET! Собираем (панель “Project Explorer” >проект “inet” >контекстное меню >“Clean Project” и “Build Project”), за процессом можно наблюдать в “Console” (Alt+Shift+Q,C).

Если все прошло хорошо, то рекомендую закрыть Eclipse, и сделать бекап файла “.cproject” и директории “.settings” с настройками проекта {B-G}, а также файлов: “.oppfeatures”, “.oppfeaturestate”, “.nedexclusions” – {A}.

Наконец, настройка завершена, и можно перейти к самому интересному.

# Создание первого проекта

Это были Simulation Manual и User Guide, позже к ним присоединился Stack Overflow (в виде stackoverflow.com, и в виде состояния мозга). Note: Первое, что я сделал после настройки окружения – стал изучать содержимое директории “doc” у OMNeT++ и INET. Ниже я покажу, как можно сделать первые шаги, не читая всю документацию, и расскажу, с какими “особенностями” можно столкнуться.

Все ссылки ведут на исходники версии 3.
Note: Для тех, кто еще не успел установить себе OMNeT++ и INET, но уже хочет посмотреть на код, текст ниже содержит ссылки на исходники INET в GitHub. 0 (эти ссылки будут доступны всегда, даже если в будущих версиях расположение файлов в INET изменится). 4.

Может в нем уже реализовано то, что нам нужно?
Перед созданием своего проекта хорошо бы посмотреть на уже готовые модели в INET, посмотреть, как они устроены.

UDP пригодится нам для broadcast рассылки.
После непродолжительного блуждания по дереву INET в “Project Explorer”, можно наткнуться на директорию “inet/src/inet/applications”, и обнаружить в ней “udpapp” (UDP Application). Там есть еще и “UDPBasicApp”, но он оказался не таким уж и “Basic”. Внутри директории лежат несколько моделей, и, судя по названию и размеру исходников, самый простой из них, это “UDPEchoApp”. Пока не ясно, зачем нужны “.ned” файлы, но судя по их содержанию (наличию строчки “parameters:”) в них могут описываться параметры модели. Каждая модель состоит из “.cc”, “.h” и “.ned” файлов.

Посмотрим, какие примеры (inet/examples) есть в INET.
Продолжим поиски интересных моделей. Этот пример помимо файлов “.cc”, “.h” и “.ned”, содержит еще “.ini” и “.xml” файлы. И нам повезло, в нем есть пример с названием “broadcast” (inet/examples/inet/broadcast)! Пора разобраться, зачем эти файлы нужны:

  • .ned – файл/язык, описывающий либо модель сети (Network), либо простейшие блоки (Simple modules) “кирпичики”, из которых можно собирать модули (Compound module). В целом это выглядит так (картинка), т.е. можно собрать модель сети, и провести несколько экспериментов не написав ни одной строчки на C++.
  • omnetpp.ini – файл, в котором можно задать/переопределить параметры модели. Если нужно провести несколько экспериментов с разными параметрами, то всех их можно перечислить (Named Configurations) в этом же файле.
  • .xml – просто файл с настройками, которые считывает один из используемых модулей (IPv4NetworkConfigurator).

в его сеть включены маршрутизаторы.
К сожалению, этот пример (“broadcast”) нам не подойдет, т.к. Однако, по аналогии с ним, можно создать свой проект.

Как видите, он достаточно большой, браузеру требуется время (и RAM) для его открытия.
Note: Далее я продолжу ссылаться на разные разделы Simulation Manual. После его запуска все ссылки, ведущие на разделы Simulation Manual, перестанут плодить вкладки (пожирая ресурсы), и начнут переключать разделы в одной единственной дополнительной вкладке (на самом деле он просто прописывает target для каждой ссылки на Simulation Manual). Для решения этой проблемы я сделал небольшой JS‑bookmarklet. И, для того, чтобы отличить ссылки на Simulation Manual от остальных ссылок, bookmarklet изменяет их цвет. Bookmarklet расположен в первом комментарии к этой статье.

Почему bookmarklet находится в комментарии, а не прямо здесь?

На Хабре авторы статей могут в любой момент изменить содержимое статьи. При повторном открытии статьи bookmarklet придется запускать заново. При первом запуске bookmarklet вы наверняка проверили, что он делает.
⇒ запускать bookmarklet из тела статьи потенциально не безопасно – они могут в любой момент изменится; если же bookmarklet размещен в комментарии, то достаточно проверить его всего один раз (по истечении 5-и минут с момента публикации комментария) – в будущем он не изменится. Содержимое комментария можно изменить только в течение первых 5-и минут.

# Создаем проект

Пустой проект “LLTR”, с директориями “src” и “simulations”, и единственной конфигурацией “gcc-release” (File → New → OMNeT++ Project…):

New OMNeT++ project Wizard

В основном, настройка будет отличаться отсутствием необходимости настраивать “gcc-debug” (т.к.
Осталось настроить проект также как и “inet”, и можно будет двигаться дальше. Более конкретно: вместо {A,B,G} надо открыть раздел “Project References”, и включить зависимость от “inet”. он отсутствует в “LLTR”), и добавлением в зависимости “inet”.

# Структура проекта

Содержимое тоже отличается – “package lltr;” и “package lltr.simulations;” соответственно.
Если посмотрите на файлы, которые создал Wizard, то увидите, что файл “package.ned” встречается дважды: в директории “src”, и в “simulations”. Один из этих файлов нам не понадобится.

То есть в “LLTR/simulations” лучше размещать файлы “.ned” c Network, а в “LLTR/src” – составные части сети (модули).
Если провести аналогию со структурой проекта INET, то директория “inet/src” – это “LLTR/src”, а “inet/examples” – это “LLTR/simulations”.

То же самое можно применить и к модулю, созданному с нуля – найти ему подходящее место в INET.
Существует еще один нюанс – в INET очень хорошая внутренняя структура директорий, и если в будущем нам потребуется изменить один из стандартных модулей в INET, то лучше будет создать новый модуль, и положить его рядом с оригиналом в INET.

Поэтому переносим “package.ned” из “LLTR/src” в “LLTR/simulations”.
В свете вышеописанного, “.ned” в директории “LLTR/src” нам не нужен (все будет в “inet/src”), также как и не нужен дополнительный подпакет “package lltr.simulations;” в “LLTR/simulations”.

# Пробный запуск

Для этого достаточно открыть файл “LLTR/simulations/omnetpp.ini”, и нажать (Run >Run As > 1 OMNeT++ Simulation):
Попробуйте запустить LLTR.

Run simulation from toolbar

Соглашаемся, и сразу же сталкиваемся с проблемой: “LLTR/src/LLTR.exe” не был найден.
При этом Eclipse предложит создать новую конфигурацию “simulations” для запуска симулятора. Все верно, ведь “LLTR.exe” никто не собирал, поэтому вначале собираем проект (меню Project → Build Project), а затем опять запускаем симулятор (тем же самым способом).

Этим мы создали пустую сеть (в “.ned” файле), и настроили (в “.ini” файле) симулятор на загрузку этой сети (Network – имя сети) при запуске.
После запуска симулятора появилось предупреждение “No network specified in the configuration.”, его можно исправить, добавив строку “network = lltr.Network” в секцию “[General]” файла “omnetpp.ini”, и добавив строку “network Network {}” в конец файла “package.ned”.

Теперь можно попробовать опять запустить симулятор (Run >Run As > 1 OMNeT++ Simulation), и вместо ошибки должно открыться серое поле (прямоугольник) сети Network на зеленом фоне.

во втором случае, перед запуском симулятора, Eclipse начинает собирать проект.
Note: Есть различие между запуском через (Run >Run As > 1 OMNeT++ Simulation), и через (Run > 1 simulations): в первом случае запуск проходит быстрее, т.к.

1.
Note: (или можно форкнуть – тег a1_v0. 1. 0 (“a” – article) “git checkout -b ‹my_branch› tags/a1_v0. 0”)

# Рекомендации по использованию репозитория

Репозиторий я создавал таким образом, чтобы:

  • каждый шажок из tutorial совпадал с коммитом в git;
  • можно было легко сослаться из tutorial на конкретный коммит – для этого каждый значимый коммит имеет свой тег;
  • можно было клонировать (скачать) к себе только коммиты, относящиеся к текущей части (article) – для этого каждая часть имеет свою ветку (формат имени: “article_#”), указывающую на последний коммит/тэг части;
  • любой смог легко создавать свою версию исходного кода из репозитория, “шагая” по tutorial.

Note: без веток “article_#” можно было бы обойтись, и указывать, при клонировании, название последнего тега части (которое еще надо найти), но с веткой проще/быстрее.

Лучше всего, вначале его форкнуть на GitHub, а затем свой форк:
Как забрать репозиторий “к себе”?

Далее, для создания личной ветки на основе конкретного тега, можно использовать “git checkout -b ‹my_branch› tags/‹tag_name›”.

изменять код?
Как создавать свою версию кода, т.е. Если в будущем не возникнет желания сделать Pull Request, то ничего вам не мешает делать с форком что хотите >:-), однако я советую, при появлении изменений, которые хочется сохранить, делать так):

Git: History Control System flow

Одинаковая схема наименования тегов поможет в будущем избежать коллизий, даже не смотря на то, что теги при Pull Request не переносятся.

Только вместо добавления “-u” к именам новых тегов тегам, я буду увеличивать номер.
Note: Если я в будущем буду вносить изменения в репозиторий, то я поступлю также: оригинальный код сохранится, а измененный будет идти параллельно оригинальному (с “накатанными” всеми изменениями из остальных (будущих) тегов, и с новыми именами тегов). 1.0”, “a1_v0. Например, теги оригинального кода “a1_v0. 1.1”, “a1_v0. 2.0”, … – теги измененного кода “a1_v0. 1.2”, “a1_v0. 2.1”, … При следующем изменении, номер еще раз увеличится: “a1_v0. 2.2”, …

Note: в tutorial все места, завершающие очередной “шажок”, помечены значком git git tag diff icon, и рядом с ним будет ссылка на соответствующий git tag.

Note: git diff использовался стандартный, патчи генерировались автоматически, и они редко будут показывать логической связи в произошедших изменениях (в частности, при добавлении нового кода и изменении уровня вложенности / форматирования существующего кода) (здесь бы пригодилось отслеживание изменений на уровне AST), похожее на этот проект для Java.

# Создание первой модели (Link Layer Topology Reveal)

# Шаг −1: собираем сеть

Откроем “package.ned” в режиме графического редактирования схемы (вкладка “Design” снизу), и попробуем набросать сеть из КДПВ:

Network editor

Сеть построена из тех же модулей, которые были использованы в примере broadcast:

  • хосты – StandardHost;
  • свитчи – EtherSwitch.

Кстати, почему именно 10 метров, где они задаются, и можно ли поменять это значение?
А вот в качестве “провода” (канала связи) выбран Eth100M (скорость: 100 Mbps; длина: 10 метров). (ответ чуть ниже)

2.
Если переключится в режим редактирования кода (вкладка “Source” снизу), то вы должны увидеть примерно это (git tag a1_v0. Пояснение структуры: 0) diff.

package ‹<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:packages">имя пакета</a>›; //<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:directory-structure">особенности наименования</a> import ‹<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:imports-and-name-resolution">имя подключаемого пакета</a>›; network ‹<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:warmup:network">название описываемой сети</a>›
{ @display(‹визуальные параметры сети, например, размер области›); <a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:submodules">submodules</a>: ‹<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:submodules">название узла</a>›: ‹тип узла› { @display(‹визуальные параметры узла, например, местоположение›); } <a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:connections">connections</a>: ‹название узла›.‹<a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-lang:gates">точка соединения</a>› <--> ‹тип канала связи› <--> ‹название узла›.‹точка соединения›;
}

И так происходит не только с этим блоком кода, но и со всеми ниже, в которых использовалась вставка ссылок, либо выделение частей кода при помощи тегов (<strong>...</strong>, <em>...</em>).
Warning: К сожалению Хабр пока не поддерживает вставку ссылок при помощи тега <a>...</a> – вместо ссылок сейчас в код “вставляются” сами теги.

Отдельно стоит сказать про “точки соединения” (Gates) и каналы связи:

  1. Gates могут быть объявлены как векторы, в этом случае подключатся к ним можно явно, указав номер gate “‹название узла›.‹gate›[‹номер›]”, либо автоматически – инкрементально‹название узла›.‹gate›++”.
  2. Параметры канала либо могут быть заданы в месте использования (например: “… <--> { delay = 100ms; } <--> …”), либо могут иметь имя/тип, на которое можно ссылаться (как в примере broadcast: “… <--> C <--> …”), либо могут иметь тип и быть переопределены на месте (например: “… <--> FastEthernet {per = 1e-6;} <--> …”), либо…
  3. Gates могут быть однонаправленными (тип при объявлении: output / input; соединители при подключении: --> / <--), и двунаправленными (тип при объявлении: inout; соединитель при подключении: <--> ). Двунаправленные состоят из двух однонаправленных, к которым можно обратиться напрямую, дописав суффикс “$i” либо “$o”.

Но даже эти 1⁄3 позволили обнаружить еще один баг в парсере.
Warning: К сожалению парсер Хабра пока смог обработать только 1⁄3 публикации за отведенные ему 20 секунд (приходит ошибка 504 “Gateway Time-out”). Небольшой пример (исходная разметка):

Выполните в точности эту <a href="#set">команду: “<code>set: p=1.87548</code>”</a> в терминале своего портативного ядерного реактора.

После парсера:

Выполните в точности эту <a href="#set"><code>команду: “set: p=1.87548</code>”</a> в терминале своего портативного ядерного реактора.

Его оригинальная разметка выглядела так:
Увидеть этот баг в действии можно, взглянув на конец 3‑го пункта в списке выше.

можно обратиться напрямую, <a href="https://omnetpp.org/doc/omnetpp/manual/#sec:ned-ref:inout-gates">дописав суффикс “<strong><code>$i</code></strong>” либо “<strong><code>$o</code></strong>”</a>.

И, чтобы не ждать окончания этого процесса, я разместил полную версию публикации на GitHub Pages:
Хорошая новость в том, что парсер сейчас переписывают.

Читать дальше →

К тому же при открытии полной версии через кнопку «Читать дальше →», активация произойдет автоматически.
Note: В полной версии я упростил активацию target у ссылок на Simulation Manual – вместо запуска bookmarklet'а, достаточно нажать на кнопку здесь.

3‑й этап – это модификация разметки под Хабр.
Note: Разметка, CSS и JS этой страницы могут показаться странными – все дело в том, что процесс подготовки публикации у меня разбит на 3 этапа, и в GitHub Pages находится немного измененный результат 2‑го этапа (обычный HTML, пригодный для просмотра в браузере, и, при этом, максимально близкий к хабра‑разметке).

# В следующих частях / To be continued…

  • 2. Алгоритм определения топологии сети по собранной статистике
  • 3. OMNeT++ продолжение
  • 4. Математика
  • 5. OMNeT++ продолжение 2
  • 6. Реализация
  • 7. Эксперимент (название‑спойлер: “в конце Джон умрет”)

# Обратная связь

Первый вопрос поможет мне лучше определить время для публикации следующей части. Небольшой опрос. Остальные вопросы – чистое любопытство. Второй – улучшить статью.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть