NS3: La clase Node

La clase Node y NetDevice, junto con el canal de comunicación, simulan el hardware de nuestra red. Un objeto de la clase Node podríamos identificarlo con un PC, un móvil, un sensor, etc. es decir cualquier dispositivo de cómputo donde vamos a instalar cosas. Al igual que los dispositivos de cómputo en la realidad, los objetos de la clase Node necesitan interfaces de red para comunicarse. Estas interfaces de red son de una tecnología específica (Bluetooth, Wifi, Ethernet, LTE, etc.). Al igual que en la realidad, un objeto Node puede tener mas de un interfaz de red. Las interfaces de red en NS3 vienen representadas por objetos de la clase específica de la tecnología que hereda de la clase abstracta NetDevice.

Por ejemplo una interfaz wifi viene representada por la clase WifiNetDevice que hereda de NetDevice.

El ejemplo mínimo de creación de un nodo lo podemos ver con el ejemplo node1.cc . Es un ejemplo que crea un único nodo y obtiene su ID. Cada nodo tiene un Id único. La variable n es, a todos los efectos, una caja vacía donde luego instalaremos y configuraremos el resto de cosas.

Si ponemos el archivo node1.cc en el directorio scratch y lo ejecutamos con NS_LOG="Node" ./waf --run node1 veremos la información del módulo Node (es lo que indicamos con NS_LOG="Node" antes del comando waf) y el identificador del nodo. Salvo que estes depurando, evita usar muchos LOG ya que ralentizan la simulación. Podemos habilitar el sistema de Log desde el código fuente tal y como veremos en otra entrada de blog.

El problema de crear los nodos de forma directa es que tienes que ocuparte de hacer todas las operaciones a todos los nodos. Para simplificar este proceso habitual en una simulación, NS3 dispone de la clase NodeContainer.

Si has echado un vistazo a la clase Node verás que es bastante sencilla, puedes instalar aplicaciones, puedes conectar interfaces de red y registrar manejadores o gestores de protocolos.

En vez de usar directamente la clase Node, usaremos la clase NodeContainer para este tipo de tareas. En NodeContainer.cc podemos ver que hay varias formas de crear un contenedor (añadiendo nodos ya creados, indicando el número de nodos a crear con Create, concatenando dos contenedores ya creados, etc.) con un aspecto importante a tener en cuenta, el número id de un nodo es único e irrepetible.

Al igual que otros asistentes que veremos, el NodeContainer es un contenedor inspirado en los contenedores STL.Como tal, se pueden iterar sobre sus elementos con un iterador (por ejemplo, la función imprimirContainerIds en NodeContainer.cc), concatenar contenedores (por ejemplo, el NodeContainer c del ejemplo), etc.

Programando en NS3

NS3 puede tener una curva de aprendizaje considerable dado que es un simulador de eventos discretos centrado en redes y, por lo tanto, tiene mucha variedad de combinaciones

Para programar cualquier ejemplo, ten en cuenta los siguientes consejos para acortar el tiempo de aprendizaje:

  • Por supuesto, el tutorial oficial es el mejor punto de partida
  • Los ejemplos (en el directorio examples) y los test (en el directorio test de cada módulo en el directorio src) del propio ns3 son la mejor fuente de información y puedes utilizarlos como plantillas para comenzar a programar
  • Para muchas de las tareas de configuración existen clases asistentes (terminada en *helper). MobilityHelper, BasicEnergySourceHelper, OlsrHelper, etc.
  • Genera los resultados en algún estándar como pcap y podrás usar herramientas externas para analizar tus resultados.
  • Utiliza un objeto de la clase NodeContainer para guardar todos tus nodos y luego utilizarlo para aplicar las mismas operaciones a todos tus nodos. Por ejemplo, poner un mismo tipo de netdevice a 100 nodos
  • A la hora de depurar, puede ser interesante habilitar el sistema de log de los diversos componentes para obtener mas información: por ejemplo LogComponentEnable (“UdpClient”, LOG_LEVEL_INFO); habilita los mensajes del componente UdpClient al nivel de info. Hay varios niveles de log. Pero ten cuidado, a mas log mas lenta va la simulación
  • Estructura tu simulación de forma que los parámetros que quieras cambiar entre simulación y simulación puedan ser pasados como argumento. Aquí tienes un ejemplo de cómo hacerlo.
  • Separa la generación de resultados, del procesamiento y análisis de los resultados. De esta forma, no tendrás que ejecutar toda la simulación de nuevo para cambiar algo del análisis
  • Para crear un nuevo modelo, lee cuidadosamente la parte del manual de soporte
  • Aunque hay muchos módulos, generalmente solo hay que configurar los módulos comunes y estructurar tu escenario de simulación. ¡Puedes ser productivo en un tiempo relativamente corto!

    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.