# Network scenario - Mininet ## Installation methods Para la instalación del escenario se ha creado un imagen Vagrant a la cual se le aprovisionan todo todos los shellscripts necesarios para la instalación/configuración del escenario. Se ha elegido para tener todos las mismas especificaciones, de esta manera, en caso de encontrar errores podremos sacar de una forma más sencilla la trazabilidad de la causa de estos. De no querer hacer uso del metodo de instalación de Vagrant se puede seguir el metodo de instalación nativo. --- ### Vagrant Hacemos un clone del repositorio: ```bash git clone https://github.com/GAR-Project/project cd project ``` Levantamos la máquina virtual: ```bash vagrant up ``` Nos conectamos a las VM: ```bash vagrant ssh test vagrant ssh controller ``` Ya deberíamos tener toda las máquinas configuradas con todas las herramientas necesarias para levantar nuestro escenario de Red con Mininet en la VM **test**, y Ryu en la VM **controller**. #### Troubleshooting - ssh connection Si direra problemas la conexión por ssh a la máquina comprobar que las keys que están en el path `.vagrant/machines/test/virtualbox/` tienen como owner el user, y los permisos de solo lectura para el owner de la key. ``` bash cd .vagrant/machines/test/virtualbox/ chmod 400 private_key # También podemos hacerlo así (u,g,o -> user, group, others) chmod u=r,go= private_key ``` En vez de usar el gestor de vagrant para realizar la conexión ssh, podemos en una última instancia hacerla nosotros mismos, indicando el path a la private key. Por ejemplo: ```bash ssh -i .vagrant/machines/test/virtualbox/private_key vagrant@10.0.123.2 ``` --- ### Native Al ser un instalación nativa se entiende que el user tiene la máquina virtual ya pre-configurada. Lo ideal sería disponer de dos VM para separa el controlador de la VM donde se emulará la topología de red. Intentar hacer uso de una distribucción Ubuntu 16.04. Hacemos un clone del repositorio: ```bash git clone https://github.com/GAR-Project/project cd project ``` Lanzamos los shellscript de aprovisionamiento, cada uno en su máquina: ```bash # Para instalar Mininet y sus dependencias. Además de telegraf sudo ./util/install_mininet.sh sudo ./util/install_telegraf.sh # Para instalar Ryu y el sistema de Monitorización (Grafana e InfluxDB) sudo ./util/install_ryu.sh sudo ./util/install_grafana_influxdb.sh ``` --- ## Our scenario Nuestro escenario de red viene descrito en el script [`src/scenario_basic.py`](https://github.com/GAR-Project/project/blob/master/src/scenario_basic.py). Mininet hace uso de una API de Python para dar la posibilidad a sus usuarios de automatizar procesos de una manera sencilla, o desarrollar ciertos modulos según la conveniencia de cada cual. Por esto y por muchas cosas más, Mininet es una herramienta altamente flexible y potente para la **emulación** de redes (Ampliamente utilizada por la comunidad científica). * Para más información acerca de la API, consultar su [manual](http://mininet.org/api/annotated.html). ![Escenario](https://i.imgur.com/kH7kAqB.png) Para el escenario planteado se ha separado el controlador en una máquina virtual y el core de la red en otra máquina virtual. En Mininet identificamos al controlador, **Ryu**, por la IP de la máquina virutal dentro de la red privada de VirtualBox y su puero de escucha. Esta separación en dos máquinas distintas, se debe a lo siguiente: * Facilitar el trabajo en equipo, ya que la **lógica con AI** irá metida directamente en la VM del controlador. De esta forma la integración del trabajo en equipo será más sencilla, independizando el core de Mininet + recolección de datos (**telegraf**) de la lógica de detección de ataques de DDoS, visualización (**Grafana** + **InfluxDB**). * Facilitar el almacenamiento de datos hacia InfluxDB desde telegraf, ya que debido al funcionamiento interno de Mininet puede haber conflictos en la comunicación de estos datos. Más adelante se detallará el funcionamiento básico de Mininet a bajo nivel. * Al separar en dos máquinas con funcionalidades claramente diferenciadas se puede hacer debug de una manera más sencilla ya que podremos identificar de forma clara cual de estos módulos (Mininet Core, Controller) dan problemas. ### How to run our scenario Para lanzar nuestro escenario deberemos estar conectados con uan terminar a la máquina virtual `test` y a la máquina virutal `controller`. En primera instancia vamos a levantar el controlador, para ello desde la máquina `controller` ejecutamos lo siguiente, es una aplicación que hace un forwarding básico, lo que necesitamos: ``` ryu-manager ryu.app.simple_switch_13 ``` ![ryu_up](https://i.imgur.com/EGyKHLT.png) Una vez levantado el controlador vamos a levantar el core de la red, para ello desde la máquina `test` vamos a lanzar el scritp mencionado anteriormente: ``` sudo python3 scenario_basic.py ``` ![mininet_up](https://i.imgur.com/DSPsPDL.png) Además se puede apreciar que desde nuestra máquina test se nos ha abierto la llamada **CLI de Mininet**. Es una interfaz de linea de comandos desde la cual se pueden hacer multitud de acciones. A continuación, se detallarán la más útiles. ### Is working properly? Ya tendriamos nuestro escenario operativo. Podemos comprobar la conectividad de nuestra red haciendo ping entre los host, por ejemplo: ``` bash mininet> h1 ping h3 # Tambien podemos hacer ping entre todos con todos con la orden pingall mininet> pingall ``` ![ping_basic](https://i.imgur.com/NhglFK5.png) <br> Como se puede ver en la imagen anterior, hay plena conectividad en nuestro escenario. Como curiosidad, **¿Por qué tarda tanto el primer mensaje de ping?** , Es normal, tenemos que tener en cuenta que el primer mensaje de ping antes de ser transmitido se deben realizar las siguientes acciones: * Resolución ARP entre emisor y receptor del ping, para así poder obtener las MACs y poder conformar los paquetes. * Además, el paquete ICMP (ping-request) va a ser redirigido al controlador para decidir que hacer con el paquete, al no tener un **Flow** especificado con una regla establecida en los switchs por los cuales va a trasncurrir el ping-request y el ping-reply. De esta manera el controlador cuando le llegue el paquete instanciará una serie de reglas en los switch para que el paquete ICMP sea encaminado de un host a otro. ![ryu_packet_in](https://i.imgur.com/lSGDeTN.png) <br> Como se puede ver, en el stdout del controlador, se indica las ordenes que ha ido instanciando en función de los paquetes que ha procesado. Al final, para el primer paquete va a tener que asumir una demora debido a la resolución ARP y a la resolución de reglas con el controlador. Pero el resto de paquetes ya dispondrán de la MAC del destino y de las reglas instanciadas en los switch intermedios, por lo que su tiempo de demora será ínfimo. --- ## Mininet CLI Ya hemos puesto apunto nuestro escenario y hemos verificado que está funcionando correctamente. Ahora detallaremos los comandos más importantes de la CLI de Mininet. ### Command: EOF + quit + exit Estos tres comandos se utilizan para lo mismo, salir de la CLI de Mininet y terminar la emulación. El source code de estos tres comandos no difieren mucho, **EOF** y **quit** terminan haciendo uso de exit al final, por lo que podríamos decir que son un poco repetitivos. ```python def do_exit( self, _line ): "Exit" assert self # satisfy pylint and allow override return 'exited by user command' def do_quit( self, line ): "Exit" return self.do_exit( line ) def do_EOF( self, line ): "Exit" output( '\n' ) return self.do_exit( line ) ``` ### Command: dpctl El comando **dpctl** es un comando de utilidad de administración que permite cierto control sobre el switch OpenFlow (ovs-ofctl en el switch OpenvSwitch). Con este comando es posible agregar flujos a la tabla de flujo, consultar las características y el estado de los switchs o limpiar la tabla entre otras muchas cosas. Por ejemplo, anteriormente hicimos un ping entre **h1** hacia **h3**, si consultamos las tablas de flujo podremos comprobar como las reglas han sido instanciadas para este tipo de flujos: ![dpctl](https://i.imgur.com/1N3yQm8.png) Se puede apreciar como se ha instanciado una regla de ida y otra de vuelta en aquellos switch por los cuales var a fluctuar nuestro ping. Este comando es muy extenso, y puede que para lo que vamos a realizar en esta práctica no sea del todo necesario, pero sin lugar a duda es uno de los comandos más importantes para entender el funcionamiento interno de los switchs SDN. Para más información, consultar la documentación del mismo: * [OpenvSwitch](http://www.openvswitch.org/support/dist-docs/ovs-ofctl.8.txt) ### Command: dump + net Estos comandos nos arrojarán información sobre la topología emulada. El comando **net** nos indicará los nombres de los entes que hay en la topología a emular y sus interfaces. El comando **dump** además nos indicará el tipo de ente, dirección IP, puerto cuando corresponda, interfaz y el identificador de proceso (pid) del ente. ![dump](https://i.imgur.com/ysCDTE5.png) ### Command: xterm + gterm Estos dos comandos nos permitirán abrir terminales en el nodo indicado. El comando **xterm** nos permitirá abrir una terminal simple, y el comando **gterm** nos permitirá abrir una gnome-terminal. Podemos abrir varias terminales a la vez indicando todos los nodos que queremos abrir una terminal en ellos. Más adelante, cuando entremos en el funcionamiento interno de Mininet, se explicarán ciertos detalles sobre donde se están ejecutando este proceso de bash, cabría pensar que este proceso está asilado de nuestra máquina sobre la cual estamos ejecutando Mininet, pero no es así del todo. ```bash # xterm/gterm [node1] [node2] xterm h1 h6 ``` ![xterm](https://i.imgur.com/YkSj6QB.png) ### Command: nodes + ports + intfs Estos comandos listarán información relativa a los nodos de la topología. El comando **intfs** listará toda la información relativa a las interfaces de los nodos. El comando **nodes** listará todos los nodos de la topología. Por útlimo, el comando **ports**, utilizado para listar los puertos e interfaces de los switches de la topología. ![intfs](https://i.imgur.com/9qNNYy1.png) ### Command: The rest of the commands :smirk: Mirarlo en con el comando **help**, o si no preguntarme directamente, no quería que esta parte creciera demasiado. Con los comandos expuestos se entiende que se cubrirán todas las necesidades del proyecto. <br> --- <br> ## Mininet Internals Como ya de indicó anteriormente Mininet es una herramienta que utiliza para **emular** redes SDN. Recalco que es importante saber la diferencia entre la **emulación** y la **simulación**. Con la simulación nosotros utilizaremos un software que calcula eventos de un comportamiento esperado, y con la emulación, recreamos todo el escenario en un hardware especifico y vemos como se comporta. Para verlo de una forma más sencilla, podriamos decir que jugar a un videojuego de aviones sería una simulación. Pero por ejemplo, prácticar en una cabina de vuelo a escala 1:1 con mandos reales se podría considerar una emulación. ![emulación](https://i.imgur.com/Pwr6MHb.jpg) Una vez entendida la diferencia, pasemos al siguiente paso. **¿Mininet Emula?** Si, Mininet emula el comportamiento de una red, para ello reserva recursos en tu máquina para cada elemento de la red a emular. Podría pensarse que que cada elemento de la red es una máquina virtual o un contenedor virtualizado.. Pero no es así, esa solución aunque tiene muchas ventajas ya que asilas completamente al nodo, tiene un contra muy importante que son los recursos que serían utilizados en la máquina host. Por lo que, por ejemplo, no seríamos capaz de emular un red bastante grande en un único equipo debido a la falta de recursos. La solución por la que optaron los desarrolladores de Mininet fue la de **virtualizar exclusivamente** lo necesario para llevar a cabo la **emulación de la Red**. ¿Cómo lo hicieron? Haciendo uso de las **Network Namespaces**. <br> ### Network Namespaces Una **network namespace** consiste en una replica lógica de stack de red que por defecto tiene el kernel de Linux, rutas, tablas ARP, Iptables e interfaces de red. Linux se inicia con un Network namespace por defecto, con su tabla de rutas, con su tabla ARP, con sus Iptables e interfaces de red. Pero también es posible crear más network namespaces no predeterminadas, crear nuevos dispositivos en esos espacios de nombres, o mover un dispositivo existente de un espacio de nombres a otro. Este es un concepto de virtualización bastante complejo que nos proporciona el kernel de linux, no voy a ir más allá :fearful:. De esta manera, cada elemento de la red tiene su propia network namespace, es decir, cada elemento tiene su propio stack de red e interfaces. Por lo que a nivel de networking como se diría se pueden ver como elementos independientes. Aunque todos ellos comparten espacio de procesos, espacio de IPCs, mismo sistema de archivos... ![example](https://i.imgur.com/4ihZdsP.png) Por ejemplo, yo en la máquina host pongo creo un proceso con PID **20483**, con el comando **sleep**. De estar aislados los elementos de la red, esto no podrían ver los procesos de la máquina host, sin embargo la realidad con Mininet es otra. Esto es algo que hay que asumir cuando se trabaja con Mininet, emulación low-cost :sweat_smile: . Aunque repito, para emular una red es más que suficiente. Lo que se deberá ver es como integrar nuestro sistema de recolección de datos (telegraf) en los distintos elementos de la red sin que haya incompatibilidades por ello. Por eso mismo se decidió sacar al controlador de esta máquina donde iba a correr Mininet, para evitar problemas de by-pass por IPCs desde telegraf hacia la base de datos InfluxDB. Por lo que solo quedaría ver como instalar telegraf y configurar correctamente para que cumpla su funcionamiento según lo acordado. --- ## Troubleshooting * Si hacemos uso de una terminal, sin **X server** por ejemplo, para reencaminar el stdout gráfico de la máquina virtual hacia afuera, la herramienta Miniedit no va a correr. Hace uso de tkinter, necesita la variable de entorno `$DISPLAY` debidamente configurada. * Si hay problemas al lanzar el escenario probar hacer un clean del enviroment anterior. Normalmente si salimos con la orden quit de la CLI de mininet se debería borrar correctamente, de no ser así siempre podemos limpiar nosotros mismos: ``` sudo mn -c ``` ![clean](https://i.imgur.com/zRrxiP5.png)