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
| Palabra | Qué significa |
|---|---|
| os-ken | una biblioteca de Python para escribir controladores OpenFlow |
| Manejador | una función que se ejecuta cuando ocurre un evento |
| Packet-in | el mensaje con el que un switch sube un paquete al controlador |
| Flow-mod | el mensaje con el que el controlador añade un flujo |
| Packet-out | el mensaje con el que el controlador manda sacar un paquete |
| Evento | algo 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
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
@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
@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 controlador | Resultado |
|---|---|---|---|
| De la MAC prohibida, la primera | No | Escribe un flujo de descarte | La trama se pierde |
| De la MAC prohibida, la segunda | Sí | No se entera | El switch la descarta solo |
| De otra MAC, cada vez | No: no se instala ninguno | La manda inundar | Siempre 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
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
sudo ovs-vsctl --may-exist add-br sw1 -- set bridge sw1 datapath_type=system protocols=OpenFlow13 fail-mode=secureSe 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
sudo ovs-vsctl set-controller sw1 tcp:127.0.0.1:6699Se 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
sudo ovs-vsctl get-controller sw1Se 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
sudo ovs-vsctl get controller sw1 is_connectedSe 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
sudo ovs-vsctl del-controller sw1Se 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.