¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Un controlador OpenFlow en Python

Después de esta lección: Puedo leer un controlador pequeño de os-ken y decir qué hace cada manejador.

Lección de 60 min6 comandosLaboratorio de redes definidas por software: Open vSwitch, Mininet y un controlador OpenFlow en una VM

Qué es un controlador OpenFlow

Un controlador OpenFlow es un programa que escucha a los switches y les responde con flujos. Con os-ken, una biblioteca de Python, un controlador pequeño cabe en unas treinta líneas.

Imagina que el campus quiere bloquear un equipo por su MAC en cuanto aparezca en cualquier switch. Un controlador lo hace una vez y el switch se encarga del resto.

Al final de esta lección

Nota

Puedo leer un controlador pequeño de os-ken y decir qué hace cada manejador.

Palabras clave

PalabraQué significa
os-kenuna biblioteca de Python para escribir controladores OpenFlow
Manejadoruna función que se ejecuta cuando ocurre un evento
Packet-inel mensaje con el que un switch sube un paquete al controlador
Flow-model mensaje con el que el controlador añade un flujo
Packet-outel mensaje con el que el controlador manda sacar un paquete
Eventoalgo que ocurre y que el programa quiere atender

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Un controlador reacciona a eventos

Un controlador no recorre la red. Espera eventos y tiene un manejador para cada uno: una función con un decorador @set_ev_cls que dice a qué evento responde.

El controlador de esta lección se llama BlockList. Descarta los paquetes de una MAC prohibida e inunda los demás. Lo vemos en tres trozos. El primero trae las importaciones y una función que añade flujos.

Importaciones y la función que añade flujos

Código: python
from os_ken.base import app_manager
from os_ken.controller import ofp_event
from os_ken.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER, set_ev_cls
from os_ken.lib.packet import ethernet, packet
from os_ken.ofproto import ofproto_v1_3

BLOCKED = "00:00:00:00:00:0c"   # la MAC que no puede hablar


class BlockList(app_manager.OSKenApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

    def send_flow(self, dp, priority, match, actions):
        # Envía al switch un mensaje flow-mod: añade un flujo.
        parser = dp.ofproto_parser
        apply_now = parser.OFPInstructionActions(
            dp.ofproto.OFPIT_APPLY_ACTIONS, actions)
        dp.send_msg(parser.OFPFlowMod(datapath=dp, priority=priority,
                                      match=match, instructions=[apply_now]))

Dos eventos: conexión y packet-in

El primer evento ocurre una sola vez por switch: se acaba de conectar. El manejador instala el flujo de prioridad 0 que sube al controlador todo lo que el switch no conozca. Es el table-miss de la lección 3.

El segundo evento, packet-in, ocurre cada vez que sube un paquete. Este manejador es el cerebro del controlador.

El manejador del switch que se conecta

Código: python
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_connected(self, ev):
        # Un switch acaba de conectarse: pide que lo que no conozca suba aquí.
        dp = ev.msg.datapath
        parser, ofp = dp.ofproto_parser, dp.ofproto
        to_me = [parser.OFPActionOutput(ofp.OFPP_CONTROLLER,
                                        ofp.OFPCML_NO_BUFFER)]
        self.send_flow(dp, 0, parser.OFPMatch(), to_me)

El manejador del packet-in

Código: python
    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def packet_in(self, ev):
        # Un paquete sin flujo ha subido desde el switch.
        msg = ev.msg
        dp = msg.datapath
        parser, ofp = dp.ofproto_parser, dp.ofproto
        frame = packet.Packet(msg.data).get_protocols(ethernet.ethernet)[0]
        if frame.src == BLOCKED:
            # Sin acciones, el flujo descarta. Así el paquete no vuelve a subir.
            self.send_flow(dp, 10, parser.OFPMatch(eth_src=frame.src), [])
            return
        actions = [parser.OFPActionOutput(ofp.OFPP_FLOOD)]
        dp.send_msg(parser.OFPPacketOut(
            datapath=dp, buffer_id=ofp.OFP_NO_BUFFER,
            in_port=msg.match['in_port'], actions=actions, data=msg.data))

Ejemplo: tres tramas ante BlockList

Trama¿Hay flujo?Qué hace el controladorResultado
De la MAC prohibida, la primeraNoEscribe un flujo de descarteLa trama se pierde
De la MAC prohibida, la segundaSíNo se enteraEl switch la descarta solo
De otra MAC, cada vezNo: no se instala ningunoLa manda inundarSiempre sube al controlador

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

El controlador es un puerto especial del switch

En OpenFlow, sacar un paquete "por el controlador" es una acción más. Los puertos especiales son números enormes que no pueden coincidir con un puerto real. La biblioteca los trae con nombre.

Este Run imprime tres números. El primero es la versión de OpenFlow (4 es OpenFlow 1.3). Los otros son el puerto del controlador y el de la inundación.

Mira la versión y los puertos especiales

Comando
python3 -c "from os_ken.ofproto import ofproto_v1_3 as o; print(o.OFP_VERSION, o.OFPP_CONTROLLER, o.OFPP_FLOOD)"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Un switch encuentra su controlador por dirección

Un switch sabe dónde está su controlador por una dirección, como tcp:127.0.0.1:6699. Se la das con ovs-vsctl set-controller.

Aquí usamos un puerto donde no escucha ningún programa. El switch lo intenta y no se conecta, y su modo secure lo deja sin reglas.

Crea sw1

Comando
sudo ovs-vsctl --may-exist add-br sw1 -- set bridge sw1 datapath_type=system protocols=OpenFlow13 fail-mode=secure

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Dale a sw1 una dirección de controlador

Comando
sudo ovs-vsctl set-controller sw1 tcp:127.0.0.1:6699

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Pregunta qué controlador tiene

Comando
sudo ovs-vsctl get-controller sw1

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Pregunta si está conectado

Comando
sudo ovs-vsctl get controller sw1 is_connected

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Quita el controlador de sw1

Comando
sudo ovs-vsctl del-controller sw1

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Un error frecuente

Advertencia

Mucha gente cree que el manejador del packet-in se ejecuta con cada paquete de la red. No es así: solo con los paquetes que no tienen flujo. Cuando el controlador instala un flujo, el switch resuelve esos paquetes y el manejador calla.

Sobre este laboratorio y su código: Laboratorio de redes definidas por software: Open vSwitch, Mininet y un controlador OpenFlow en una VM

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.