Creando un nuevo módulo en NS3

[Actualizado a cmake, versión 3.36.1 (documentación oficial ns3.36)]
Crear un nuevo protocolo o algoritmo en NS3 es un paso que implica la creación de un nuevo módulo. Obviamente, a partir del tipo de protocolo o algoritmo a implementar, los pasos a seguir y los protocolos que nos servirán como referencia cambiarán. En cualquier caso, siempre necesitaremos generar un nuevo módulo e incluirlo en la compilación de NS3 para poder hacer simulaciones con posterioridad.

Para crear un nuevo módulo, NS3 nos proporciona un script python, create-module.py, dentro de la carpeta src de nuestra instalación de ns3.
Si por ejemplo queremos crear un nuevo protocolo inalámbrico, pongamos el protocolo weightlessp, si ejecutamos:

$utils/create-module.py weightless
Creating module /home/felix/tools/ns-3-dev-git/contrib/weightless
Successfully created new modules
Run './ns3 configure' to include them in the build

Se nos crea la plantilla dentro de src:

$cd contrib/weightless/
felix@homer-esi:~/tools/ns-3-dev-git/contrib/weightless$ ls
CMakeLists.txt doc examples helper model test

donde vemos las carpetas habituales para meter la documentación, los ejemplos, los asistentes, el modelo propiamente dicho y los test. También me genera el archivo CMakeList.txt que utiliza ns3 para compilar los módulos. Para ver que se incluye correctamente en el proceso de compilación:

$./ns3 configure --enable-example --enable-test
$./ns3 build
$./test.py -s weightlessp
.
PASS: TestSuite weightlessp
1 of 1 tests passed (1 passed, 0 skipped, 0 failed, 0 crashed, 0 valgrind errors)
.

Ahora falta, obviamente, lo difícil, que es programar el modelo propiamente dicho identificando cada una de las partes. Lo más recomendable es estudiar cuidadosamente un protocolo existente de la misma capa que el que queremos programar y copiar su estructura adaptando el comportamiento a la funcionalidad deseada.

Un paseo por la consola de GNU/Linux

La consola de GNU/Linux es una herramienta muy útil para gestionar y administrar el sistema operativo. Es una herramienta que es imprescindible controlar por parte de cualquier profesional de la Informática. Vamos a ver en esta y en posteriores entradas cómo gestionar aspectos básicos del sistema operativo GNU/Linux, concretamente, usaremos una Debian 10.

La consola ejecuta un intérprete de comandos, esto es, un programa que acepta comandos y los ejecuta. El intérprete de comandos que vamos a usar se llama bash. La consola cuando se inicia nos da información de la máquina, usuario y directorio donde se encuentra. En la figura podemos ver cómo se presenta dicha información, generalmente «usuario@nombre-computador: Directorio donde estás$», despues del dolar ($) podemos empezar a poner órdenes en forma de comandos que se ejecutarán cuando presionemos intro. Esta información es configurable pero lo más habitual es mostrar esa información.

El usuario es el nombre del usuario que está ejecutando los comandos, es importante de cara a qué puede hacer y qué puede ejecutar (temas de permisos que veremos en otra entrada). El nombre del computador también es relevante, ya que la consola se usa para administrar de forma remota otros computadores y se necesita saber dónde estás ejecutando comandos. El directorio donde estás es importante para encontrar los archivos y las rutas relativas, que también veremos mas tarde. El simbolo ~ representa el directorio de trabajo del usuario, que en GNU/Linux está en /home/usuario.
Con esta información, en la figura, nos encontramos con que el usuario alumno, se encuentra en la máquina cuyo nombre es alumno-pc y en el directorio de trabajo suyo por defecto, es decir, el equivalente en Windows a C:\Usuarios\alumno.

Una vez iniciada la consola, podemos empezar a ejecutar comandos, por ejemplo, en la siguiente animación vemos como ejectuamos el comando pwd que le dice a la consola que imprima el directorio donde estas y luego ejecutamos el comando whoami que le dice a la consola que imprima el usuario con el que estamos logeados. Después de introducir el comando o la orden, debemos pulsar la tecla intro para que se ejecute.
Consola

Podemos ver la consola como la caja de herramientas por excelencia de los profesionales de la informática con un montón de herramientas (comandos) para multitud de propósitos. En próximas entradas vamos a ver cómo sentirnos cómodos en la consola explorando cómo ejecutar comandos con opciones, cómo encontrar archivos y las rutas de directorios, cómo ejectuar nuestros propios archivos (e.j archivos python) y gestionar permisos y cómo instalar nuevas herramientas.

Configuración del entorno (VScode) y ejecución de ejemplos en NS3

Actualizado a la versión 3.36 (Mayo 2022)
Mi recomendación antes de nada, una vez instalado NS3 y comprobado que funciona mediante el paso de los correspondientes test (un paso imprescindible), es que configures un entorno de desarrollo adecuado para maximizar tu productividad. Un buen editor de código fuente es Visual Studio Code

En Linux, si abres el editor dentro del directorio de ns3 (en mi caso ns-3.36):

~/tools/ns-allinone-3.36/ns-3.36/$code .

se crea una carpeta .vscode con un archivo c_cpp_properties.json. En ese archivo tenemos que añadir la ruta donde están los .h, el auto completado se habilitará:

{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/build/include/ns3/**",
"/home/felix/tools/ns-allinone-3.36/ns-3.36/build"
],
"defines": [],
"compilerPath": "/usr/bin/clang-11",
"cStandard": "c17",
"cppStandard": "c++14",
"intelliSenseMode": "linux-clang-x64",
"compileCommands": "${workspaceFolder}/cmake-cache/compile_commands.json"
}
],
"version": 4
}

Una buena forma de empezar es ejecutar aquellos ejemplos que más te interesen del directorio examples.
Por ejemplo (En negrita los comandos ejecutados):

ns-3.36$ ./ns3 run wifi-simple-adhoc
...
Testing 1 packets sent with receiver rss -80
Received one packet!

Si editas los ejemplos, ahora podrás ver qué métodos y argumentos tiene cada objeto que manipules en tu simulación. Si no lo ves es que tienes las sugerencias deshabilitadas. Puedes habilitarlas siguiendo estas instrucciones

Tus trabajos se harán en el directorio scratch. En el caso de los ejemplos (dentro del directorio examples) que vienen con NS3 no es necesario copiarlos en el directorio scratch y se pueden ejecutar directamente.

El script ns3 es una herramienta de configuración y compilación escrita en python y que es usado en el proyecto NS3 para hacer de interface con el sistema cmake. Se puede usar para configurar y construir el propio NS3.

De momento, nosotros solo nos interesa para compilar y ejecutar nuestros ejemplos. Dentro del directorio de ns3 (~/tools/ns-allinone-3.36/ns-3.36 en mi caso), la sintaxis del comando a ejecutar es:

ns-3.36$./ns3 run ejemplo

Si no es un ejemplo de los que vienen con ns3, buscará ejemplo.cc en el directorio scratch, lo compilará y lo ejecutará.

Topología de los nodos en NS3

Sobre todo en simulaciones que tienen nodos inalámbricos, después de crear los nodos debes posicionarlos para formar tu topología. Topologías habituales en simulaciones son en forma de matriz cuadrada, en línea, en estrella con el nodo que hace de pasarela en el centro, etc.

El emplazamiento de un nodo (X,Y,Z) generalmente se hace con la ayuda de un objeto de la clase MobilityHelper que permite crear escenarios con posiciones donde luego emplazamos nuestros nodos (almacenados en un contenedor del tipo NodeContainer).
Es decir, configuramos una topología concreta con el MobilityHelper y luego instalamos en esa topología los nodos creados y configurados de acuerdo a los requisitos de la simulación.
Una configuración sencilla en matriz 2D sería:

MobilityHelper mobility;
mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
"MinX", DoubleValue (0.0),
"MinY", DoubleValue (0.0),
"DeltaX", DoubleValue (distanceX),
"DeltaY", DoubleValue (distanceY),
"GridWidth", UintegerValue (nodesgridwidth),
"LayoutType", StringValue ("RowFirst"));
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");

En primer lugar se le indica que vamos a crear puntos de acuerdo a ns3::GridPositionAllocator . Esto es importante por que el resto de argumentos que viene a continuación va en función de este primer argumento. El resto indica las coordenadas iniciales (MinX, MinY) en 0,0 , con una separación determinada, en este caso indicado por distanceX y distanceY, con una anchura indicado por la variable nodesgridwidth empezando por las filas (RowFirst). Por último indicamos que los emplazamientos son fijos «ns3::ConstantPositionMobilityModel».

En el repositorio de este tutorial podemos ver algunos ejemplos de base para topologías habituales. Los parámetros de entrada son configurables por línea de comandos de cara a permitir la simulación automática de varias topologías.

También en simulaciones inalámbricas, una vez emplazados, es posible que quieras mover tus nodos, para lo cual tendrás que configurar el escenario de acuerdo a tu modelo de movilidad

Otra posibilidad que te permite ns3 es la de leer topologías de un archivo donde has almacenado la posición de algunos nodos.Los inputs readers te permiten este tipo de lecturas ad-hoc y generar topologías personalizadas y/o concretas.