Try   HackMD

Mininet Internals (II)

En esta segunda parte sobre el funcionamiento interno de Mininet, indagaremos sobre la topología a nivel de Kernel recreada por Mininet para levantar nuestro escenario. Por último, explicaremos las distintas formas de levantar servicios en las distintas Network namespaces, necesario para recolectar información con telegraf.

Is Mininet using Network Namespaces?

Hemos introducido anteriormente que Mininet hace uso de Network namespaces como método para virtualizar stacks de red independientes entre sí, y así poder emular redes a un coste mínimo, pero, ¿Cómo podemos estar tan seguros de que realmente hace uso de ellas? A continuación, se indican los pasos seguidos para poder verificar si Mininet hace uso de Network namespaces, o no.

Lo primero que debemos hacer es levantar el escenario para que así, mininet, cree las Network namespaces que tenga que crear. Además, también podemos levantar el controlador en la máquina controller para comprobar en el último momento que ninguna de las verificaciones realizadas han afectado al funcionamiento de nuestro escenario.

# En la máquina test, para levantar la topolgía.
sudo python3 scenario_basic.py

# En la máquina controller, para levantar el controlador
ryu-manager ryu.app.simple_switch_13

Ahora que ya hemos levantado el escenario deberíamos ser capaces de poder ver si hay Network namespaces en nuestra máquina, para ello haremos uso del pack de herramientas iproute2. Dentro de este pack nos quedaremos con la herramienta más famosa, ip. La herramienta ip se está consolidando en las nuevas distribuciones linux como la herramienta de facto para trabajar en todo lo que a Networking se refiere en un enviroment Linux. En las últimas versiones por ejemplo de Ubuntu, el comando ifconfig está empezando a ser sustituido por el pack de herramientas iproute2 (a.k.a ip). Esta herramienta tiene muchos módulos, para más información consultar su manual:

  • Manual herramienta ip

El módulo que necesitaremos para trabajar con Network namespaces es netns, podemos ver todo lo que nos puede ofrecer haciendo ip netns help. El comando por excelencia para listar las Network namespaces haciendo uso del módulo netns es el siguiente:

sudo ip netns list

Sabiendo el comando para listar Network Namespaces, y habiendo levantado previamente el escenario, vamos a comprobar si de verdad hay Network Namespaces creadas en nuestra máquina:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


Oops

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
, parece que no hay ninguna Network namespace creada, puede que, ¿Mininet no funcione como decíamos anteriormente? Antes que nada, calmémonos, no hay que reescribir toda la documentación..

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Not today
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

El problema de que el comando ip netns list no nos arroje información, es que mininet no está creando el softlink requerido para que la herramienta sea capaz de listar las network namespaces, si leemos la documentacion podemos averiguar que ip netns list lee del path /var/run/netns/ donde se encuentran todas las Network namespaces con nombre.

Si has llegado hasta este punto probablemente quieras comprobar que iproute2 lee realmente de donde dice que lee. Podemos sacar una traza del sistema, es decir, recopilar todas las syscalls realizadas por un programa y hacer debug por nosotros mismos. Para ello haremos uso del comando strace para más información consultar su manual.

El comando que emplearemos para sacar la traza de syscalls es el siguiente:

sudo starce ip netns list 

A continuación, el output obtenido (Tratar de hacer zoom en la imagen):

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


Fijémonos bien en las cuatro últimas lineas. Si no se viera correctamente en la imagen, son estas lineas:


open("/var/run/netns", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/var/run/netns", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
exit_group(0)                           = ?
+++ exited with 0 +++

Se va a omitir la primera parte de la traza ya que lo único que hace es, parsear los parámetros introducidos, cargar funciones de librerías dinámicas muy básicas en Linux ( Archivos *.so, shared objects, por ejemplo, cache, libc entre otras). Nos quedaremos con las últimas lineas de la traza donde se puede ver perfectamente como trata de hacer un open, en modo lectura del directorio, pero este no existe.

Por lo que podemos afirmar que el comando de ip netns list si que funciona correctamente. Pero, entonces, ¿Dónde se encuentran las Network namespaces usadas por Mininet?

Where are Mininet's Network Namespaces located?
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Bien para responder esta pregunta, debemos entender primero una cosa. La herramienta ip con su módulo netns actua como wrapper a la hora de trabajar con las Network namespaces. Las Namespaces (hay varios tipos) tienen una vida finita, es decir, estas viven siempre y cuando estén referenciadas. Una namespace puede ser referenciada de tres maneras:

  • Siempre y cuando haya un proceso corriendo dentro de esta namespace.

  • Siempre que haya abierto un descriptor de archivo al fichero de la namespace. (/proc/{pid}/ns/{tipo_namespace})

  • Siempre que haya un bind mount del fichero (/proc/{pid}/ns/{tipo_namespace}) de la namespace en cuestión.

Si ninguna de estas condiciones se cumple, la namespace en cuestión es eliminada. Si se trata de una namespace del tipo net (a.k.a Network Namespace) aquellas interfaces que se encuentre en la namespace en desaparición volverán a la namespace por defecto. Una vez entendido este concepto, debemos recapacitar sobre la naturaleza de las Network namespaces que crea Mininet.

Mininet cuando se lanza crea una red emulada, cuando se cierra esta debe desaparecer, este proceso debe ser lo más ligero y rápido posible para así ofrecer una mejor experiencia al usuario. La naturaleza de las necesidades de Mininet nos incita a pensar que la creación y destrucción de las Network namespaces vienen asociadas a la primera condición de refereciación de una namespace. Es decir, no tendría sentido hacer mounts ni softlinks que a posteriori se deberán eliminar, ya que supondría una carga de trabajo bastante significativa para emulaciones de redes grandes y un aumento del tiempo destinado a la limpieza del sistema una vez que la emulación haya terminado. Además, debemos tener en cuenta que hay una tercera condición que es bastante idónea con las necesidades de Mininet, ya que solo es necesario un proceso corriendo por cada Network namespace, y a la hora de limpiar unicamente debemos terminar con los procesos que sostienen las Network namepsaces.

Just a hypothesis?

Bien, según el razonamiento expuesto, deberíamos ver varios procesos que son creados a la hora del levantamiento de nuestro escenario en Mininet. Estos procesos deberán tener cada uno un fichero de Network Namespace, /proc/{pid}/ns/net, con un inode distinto para aquellos procesos que corren en distintas Network namespaces. ¿Por donde empezamos a buscar?

Vamos a levantar el escenario si es que no lo habíamos levantado anteriormente, listar todos procesos, y filtrar por el nombre de mininet. A ver que encontramos

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
.

sudo ps aux | grep mininet

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Vaya

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
! Sin haber creado ningún proceso asociado a cada nodo de nuestro escenario, ya hay un proceso corriendo una bash asociado a cada elemento del escenario en el inicio de la emulación. Qué curioso ¿Verdad? Vamos a indagar un poco más.

Si inspeccionamos el fichero /proc/{pid}/ns/net para cada proceso podremos ver cuales de ellos están en una Network namespace distinta en función del valor que tenga el inode. Por ejemplo, vamos a comprobar los procesos asociados a los Host1 y Host2.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Como se puede ver, inode distintos, ficheros distintos, distintas Network namespaces. Para que se vea de una forma más evidente vamos a ejecutar un comando para sacar que interfaces están asociadas a cada Network namespace. Para poder inyectar procesos dentro de una namespace haremos uso de la herramienta nsenter. Para más información sobre esta herramienta, consultar su manual.

nsenter --target <pid> --net {Comando}

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Si nos fijamos en el comando introducido en cada Network namespace es el mismo, ip addr show (a.k.a ip a s). Con este comando podremos listar todas las direcciones asignadas a cada interfaz de la Network namespace. El resultado obtenido de la ejecución de cada comando es el esperado, en la Network namespace del Host1 podemos ver que existe la interfaz h1-eth0, y en la Network namespace del Host2 la interfaz h2-eth0. Con esta prueba acabamos concluimos con la existencia de las de las Network namespace de las cuales hace uso Mininet.

De forma adicional podemos corroborar nuestra hipótesis cambiando la "verbosidad" de nuestro script, donde construimos toda la topología del escenario, src/scenario_basic.py, podemos cambiar el nivel de info por debug, y lanzar de nuevo el script.

if __name__ == '__main__':
    #setLogLevel('info')
    setLogLevel('debug')
    scenario_basic()

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Como se puede ver en la ejecución se crean veth (Virtual Ethernet devices), y los distintos procesos que sostendrán las distintas Network Namespaces. Además, se ha podido comprobar como se hace uso del tc (Traffic Controller) para establecer los limites de ancho de banda, y de cola máxima a los enlaces del escenario.

So, It's possible to use iproute2 with Mininet?
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

La respuesta rápida y sencilla en el estado actual sería que no. Siempre podemos hacer uso de la API de Python para correr cosas dentro de un elemento de la red o si no, en última instancia podemos abrir la CLI de Mininet, abrir una xterm y lanzar cosas a mano, o como hemos hecho antes hacer uso de la herramienta nsenter.

Entonces, ¿No tiene solución

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
? Bueno a ver, casi todo tiene solución, de nosotros depende hasta que punto queremos llegar para arreglar las cosas. Veamos como podemos habilitar la Network namespace del Host1 para que sea visible para ip netns.

En primera instancia debemos localizar el PID de la bash que sostiene la Network Namespace del Host1. En nuestro caso es la siguiente:

sudo ps aux | grep mininet | grep h1

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Una vez conocido el PID del proceso que sostiene la Network Namespace del Host1, vamos a crear el directorio /var/run/netns en caso de que no esté creado:

# Hacemos uso del parametro -p para que en caso de que exista no nos de errores.
mkdir -p /var/run/netns/

Por último, debemos hacer un softlink del fichero de la Network Namespace original en el directorio creado (Que recordemos que es el path de donde lee el comando ip netns list).

sudo ln -sfT /proc/<PID>/ns/net /var/run/netns/h1

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Por último, solo nos quedaría probar de nuevo el comando ip netns list para ver si es capaz de listar la Network namespace:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Algunos dirán que es mágica oscura.. Pero, es solo eso, crear un softlink y saber como funciona cada elemento

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Como se puede apreciar, el comando es completamente funcional. Se puede ver como somos capaces de listar todas las interfaces de la Network namespace del Host1. Pero como todo, siempre tiene puntos a favor y puntos en contra, al hacer el arreglo de crear un softlink y apagar la emulación con su correspondiente limpieza del sistema (Sobretodo nos importa la eliminación de los procesos que sostenían la Network namespace), nos quedamos un softlink roto apuntando a un sitio que ya no existe, o que ya no es útil.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Con todo lo expuesto en este apartado se deja a valoración del usuario el hecho de que quiera hacer uso de la herramienta iproute2, o no hacerlo. De hacerlo se recomienda que se desarrolle un script auxiliar de limpieza que limpie aquellos softlinks que estén rotos en el directorio /var/run/netns a la hora de terminar la emulación.

The Big Picture

Una vez que ya hemos concluido que Mininet hace uso de Network namespaces y ya sabemos como demostrarlo, vamos a inspeccionar cada una de las Network namespaces para trazar un esquema de como está implementado nuestro escenario a nivel de Kernel. Recordemos como era nuestro escenario:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Como se ha podido comprobar los switchs al ser elementos de la red se supondría que estarían aislados en un Network namespace, pero para nuestra sopresa no es así se encuentran en la Network namespace por defecto. ¿Por qué funciona entonces, por que no se produce un by-pass al stack de red por defecto? Esto es así por la propia naturaleza de las veth, que van directas al propio proceso de OVS (En otra guía futura se intentará abordar este tema con una mayor amplitud).


Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


¿Cómo se vería entonces nuestro escenario a nivel de Kernel?

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Por lo que, para correr telegraf únicamente en los switchs nos bastaría con lanzarlo en la Network namespace por defecto! Esto lo podremos hacer con un único proceso de telegraf ya que las interfaces útiles están todas en la misma Network namespace

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
.

References