Benutzer-Werkzeuge

Webseiten-Werkzeuge


einstieg-in-sdn-mit-mininet-vm-und-ryu-controller

Dies ist eine alte Version des Dokuments!


Software-Defined-Network (SDN) Einstieg (ohne Hardware) mit Mininet VM und Ryu SDN Controller

Aller Anfang ist schwer oder doch nicht? Die virtuellen Maschinen von SDN Hub machen uns den Einstieg leicht(er)!

Ziel dieses Artikels ist es einen Überblick zu Software-Defined-Network (SDN) mit Mininet und Ryu zu geben, ohne dafür spezielle Switch-Hardware zu benötigen.

Voraussetzungen

  • SDN Hub „All-in-one SDN App Development Starter VM“ herunterladen
  • Virtualbox, dort wird die heruntergeladene VM (OVA) importiert

Einstieg

Die virtuelle Maschine bringt eine Vielzahl von SDN Controllern bereits mit. Wir fokussieren uns in diesem Artikel allerdings auf Ryu.

Ryu ist ein SDN-Controller der von der NTT (Nippon Telegraph and Telephone Corporation) entwickelt wird. In Europa kennt man vielleicht eher die Tochtergesellschaft Dimension Data.

Mir gefällt dieser Controller besonders gut, da die Community (ryu-devel Mailingliste) sehr hilfsbereit ist. Es fällt auf dass die Entwickler sich selbst Zeit nehmen um auf Fragen zu reagieren und den Controller auch auf Anfragen hin weiterentwickeln wenn eine API o.ä. bisher nicht vorhanden ist. Ryu ist in Python entwickelt und kommt mit diverse Beispielapplikationen mit denen man testen kann. (Natürlich kann man Ryu auch selbst erweitern, dies würde aber den Rahmen dieses Artikels sprengen! :))

Neben dem SDN Controller ist in der VM auch Mininet enthalten. Mininet erlaubt es uns neben einem oder mehreren Switches auch noch Clients/Teilnehmer am Netz zu simulieren.

Jeder der hier angesprochenen Bausteine hätte seinen eigenen kilometerlangen Artikel verdient, aber heute möchte ich nur Starthilfe geben. :)

Mininet

Was ist nun zu tun um folgendes Netz zu simulieren?

$ sudo mn --topo single,4 --mac --controller remote --switch ovsk,protocols=OpenFlow13

Bedeutung der einzelnen Befehlselemente

  • –topo ⇒ Topologie
    • –topo single,4 ⇒ ein Switch, vier Teilnehmer/Hosts
    • Weitere Optionen: linear, tree
  • –mac ⇒ Einfache MAC-Adressen z.B. 00:00:00:00:00:01 für Host 1
  • –controller remote ⇒ Unser SDN Controller soll nicht aus Mininet kommen (wir wollen ja Ryu verwenden, kommt im nächsten Kapitel)
  • –switch ovsk,protocols=OpenFlow13 ⇒ Verwendung des OpenVSwitch mit OpenFlow Standard v1.3
  • (Optional) –link tc,bw=10,delay=10ms ⇒ Dies würde die Bandbreite auf 10Mbit begrenzen und künstlich eine Verzögerung (Delay) auf die Links legen

Nach dem Start begrüßt uns die Mininet-Shell

$ sudo mn --topo single,4 --mac --controller remote --switch ovsk,protocols=OpenFlow13
*** Creating network
*** Adding controller
Unable to contact the remote controller at 127.0.0.1:6633
*** Adding hosts:
h1 h2 h3 h4 
*** Adding switches:
s1 
*** Adding links:
(h1, s1) (h2, s1) (h3, s1) (h4, s1) 
*** Configuring hosts
h1 h2 h3 h4 
*** Starting controller
*** Starting 1 switches
s1 
*** Starting CLI:
mininet>

Kommandos in Mininet

Anzeige der Elemente / Nodes

mininet> nodes
available nodes are: 
c0 h1 h2 h3 h4 s1
mininet> net
h1 h1-eth0:s1-eth1
h2 h2-eth0:s1-eth2
h3 h3-eth0:s1-eth3
h4 h4-eth0:s1-eth4
s1 lo:  s1-eth1:h1-eth0 s1-eth2:h2-eth0 s1-eth3:h3-eth0 s1-eth4:h4-eth0
c0

Detaillierte Anzeige der Konfiguration

mininet> dump
<Host h1: h1-eth0:10.0.0.1 pid=10802> 
<Host h2: h2-eth0:10.0.0.2 pid=10803> 
<Host h3: h3-eth0:10.0.0.3 pid=10804> 
<Host h4: h4-eth0:10.0.0.4 pid=10805> 
<OVSSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None,s1-eth3:None,s1-eth4:None pid=10808> 
<RemoteController c0: 127.0.0.1:6633 pid=10795> 

Befehl im Kontext eines Teilnehmers / Hosts ausführen

mininet> h1 ifconfig
h1-eth0   Link encap:Ethernet  HWaddr 00:00:00:00:00:01  
          inet addr:10.0.0.1  Bcast:10.255.255.255  Mask:255.0.0.0
          inet6 addr: fe80::200:ff:fe00:1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:648 (648.0 B)  TX bytes:1068 (1.0 KB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:672 (672.0 B)  TX bytes:672 (672.0 B)

Ping von h1 zu h2 ausführen

mininet> h1 ping h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
From 10.0.0.1 icmp_seq=1 Destination Host Unreachable
From 10.0.0.1 icmp_seq=2 Destination Host Unreachable
From 10.0.0.1 icmp_seq=3 Destination Host Unreachable
^C
--- 10.0.0.2 ping statistics ---
5 packets transmitted, 0 received, +3 errors, 100% packet loss, time 4024ms
pipe 3

Wir haben noch keinen SDN-Controller der die Kommunikation ermöglicht, daher ist dieses Ergebnis zu diesem Zeitpunkt erwartet.

Öffnen eines xterm Fensters für Teilnehmer / Hosts

mininet> xterm h1

SDN-Controller: Ryu

Damit unsere Ping-Aktivitäten nicht weiter fehlschlagen, brauchen wir nun einen SDN-Controller.

Start von Ryu

$ cd /home/ubuntu/ryu && ./bin/ryu-manager --verbose ryu/app/simple_switch_13.py

Bedeutung der einzelnen Befehlselemente

  • ./bin/ryu-manager ⇒ Ryu-Manager der für uns die eigentliche Applikation startet
  • –verbose ⇒ Gibt mehr Details auf der Konsole aus
  • ryu/app/simple_switch_13.py
    • Im Verzeichnis /app befinden sich viele Beispielapplikationen
    • simple_switch_13.py ist ein normaler Switch mit OpenFlow v1.3 Unterstützung

Im Fenster oben können wir sehen dass sich unser Mininet Switch mit dem Controller verbindet. Es werden im Rahmen dieser Anmeldung auch die Fähigkeiten (Features) mitgeteilt. Wenn man dem Switch später referenzieren möchte, wird dafür die „datapath_id“ (DPID) und nicht die IP-Adresse verwendet.

Im Rahmen dieses Artikels ist es nicht wirklich relevant welche „Buffer“ oder „Table“-Fähigkeiten der virtuelle Switch hat, dies ist aber später auf physikalischen Switches sehr wichtig zu wissen.

Erkunden der SDN-Lösung: Relevante OpenFlow Details

OpenFlow Kommunikation zwischen Mininet Switch und Ryu

Um sehen zu können was passiert, sollte der in der VM enthaltene Wireshark gestartet werden. Damit wir darin alle Schnittstellen sehen, ist es notwendig diesen mit „sudo“ zu starten.

$ sudo wireshark &

Da wir alle Kommunikation lokal abwickeln, sollte um die OpenFlow-Kommunikation zu sehen auf der Loopback: lo Schnittstelle mitgeschnitten werden.

Loopback: lo Schnittstelle in Wireshark auswählen!

Anzeige der hinterlegten Flows

Bevor wir jetzt zwischen den Teilnehmern / Hosts pingen, sollten wir uns die hinterlegten Flows im OpenVSwitch (OVS) anschauen.

mininet> dpctl dump-flows --protocols OpenFlow13
*** s1 ------------------------------------------------------------------------
OFPST_FLOW reply (OF1.3) (xid=0x2):
 cookie=0x0, duration=3026.918s, table=0, n_packets=0, n_bytes=0, priority=0 actions=CONTROLLER:65535

Dieser Flow besagt: Alles zum Controller schicken! Normalerweise ist dies die „Regel des letzten Auswegs“ (sonst würde der Datenverkehr verloren gehen!). Der OVS wird also alles, was an Daten an ihn herangetragen wird, an den SDN-Controller schicken. Der SDN-Controller wird dem OVS daraufhin sagen wie er in Zukunft mit solchen Paketen/Flows umzugehen hat.

Der erste Ping

Genug mit der Theorie, ich will pingen!

mininet> h1 ping h2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=210 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.963 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=0.092 ms
64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=0.086 ms
64 bytes from 10.0.0.2: icmp_seq=5 ttl=64 time=0.096 ms
^C
--- 10.0.0.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4001ms
rtt min/avg/max/mdev = 0.086/42.443/210.978/84.268 ms

mininet> dpctl dump-flows --protocols OpenFlow13
*** s1 ------------------------------------------------------------------------
OFPST_FLOW reply (OF1.3) (xid=0x2):
 cookie=0x0, duration=4169.600s, table=0, n_packets=3, n_bytes=182, priority=0 actions=CONTROLLER:65535
 cookie=0x0, duration=145.181s, table=0, n_packets=6, n_bytes=532, priority=1,in_port=3,dl_dst=00:00:00:00:00:01 actions=output:1
 cookie=0x0, duration=145.075s, table=0, n_packets=5, n_bytes=434, priority=1,in_port=1,dl_dst=00:00:00:00:00:02 actions=output:3
mininet> 

Wie man sehen kann, wurden dadurch zwei neue Flow-Einträge erzeugt. (Außerdem kann man sehen wieviel Pakete/Bytes diese Vorgänge erzeugt haben.)

Woher kommen diese Einträge?

Durch den Eintrag dass alle unbekannten Daten an den Controller gesendet werden, hat Ryu diese Anfragen erhalten und entschieden was damit zu tun ist.

Im Wireshark können wir nun auch eine Reihe von neuen Paketen sehen (wichtig ist hier nach „OFPT_PACKET_IN“ zu gucken).

Schritt 1: PACKET-IN

Dies ist der Versuch von h1 den Partner h2 zu erreichen. Da h1 nicht weiß welche MAC-Adresse h2 hat, wird zuerst ein ARP-Request zum Auflösen der h2-IP → MAC-Adresse gesendet. Außerdem ist oben die Information enthalten auf welchem OFB-IN-Port (1) das Paket reingekommen ist. Wir müssen auch besondere Aufmerksamkeit auf die Buffer ID: 256 legen, denn hier hat der OVS das Paket abgespeichert bis der SDN-Controller ihm sagt wie damit zu verfahren ist.

Schritt 2: PACKET-OUT

Da auch der SDN-Controller bisher keine Übersicht hat, was wo angeschlossen (wenn auch virtuell) ist, wird der OVS instruiert das Paket auf alle Ports außer dem eingehenden zu senden (flood). Hier kann man auch die im vorherigen Schritt verwendete Buffer ID: 256 wiederfinden (damit weiß der OVS um welches Paket es geht).

Schritt 3: PACKET-IN

Durch den „Flood“ hat h2 den ARP-Request erhalten und antwortet nun mit einem ARP-Reply. Der OVS hat für diese Kommunikation bisher noch keinen vollständigen Flow-Eintrag, daher landet auch dieses Paket beim Controller (Buffer ID: 257).

Schritt 4-1: FLOW-MOD

Nun passiert etwas sehr wichtiges, der SDN-Controller fügt einen Flow-Eintrag hinzu da jetzt genug Informationen über die Kommunikation vorliegen. Dieser bedeutet: Wenn ein Paket auf OFB-IN-PORT 3 (dort ist h2 angeschlossen) reinkommt und als Ziel die MAC-Adresse (ETH-DST) von h1 hat, dann sende das Paket auf OF-PORT 1 raus. (Dies vermeidet dass für weitere Pakete dieser Art der Controller gefragt werden muss.) Besonderheit: Ryu referenziert in diesem Fall nicht die Buffer ID: 257, was man eigentlich hätte tun können damit dieser Flow nicht nur im OVS eingetragen wird sondern das Paket auch gleich so behandelt wird. Ob dies eine Spezialität dieser Ryu-Beispielapplikation ist, muss ich noch testen.

Schritt 4-2: PACKET-OUT

Hier referenziert Ryu nun die Buffer ID: 257 und instruiert den OVS das Paket auf OF-Port 1 zu senden.

Schritt 5: PACKET-IN

Hier geht nun der eigentliche „Ping“ von h1 zu h2 los. Vielleicht fragt ihr euch nun warum das Paket hier wieder im SDN-Controller landet obwohl wir nun eben beim „ARP“ dies schonmal durchlaufen haben (Buffer ID: 258): Es handelt sich erstmalig aus dieser Richtung um ein Paket das alle Informationen enthält (inkl. der Ziel-MAC-Adresse von h2, bisher war die im ARP-Request nämlich 00:00:00:00:00:00 bzw. ff:ff:ff:ff:ff:ff gesetzt!)

Schritt 6-1: FLOW-MOD

Hier kann man nun den Eintrag des Flows von OFB-IN-PORT 1 zu h2 (ETH_DST) sehen.

Schritt 6-2: PACKET-OUT

Hier nun abschließend die Instruktion an den OVS das Paket an Buffer ID: 258 auf OF-Port 3 rauszuschicken.

Mininet Flow-Table

Mit allem was wir uns angeschaut haben, machen diese Einträge nun auch Sinn!

  • Bei eingehenden Paket auf Port (in_port) 1 mit dem Ziel dl_dst=00:00:00:00:00:02 (dl = Data Link)
    • Aussenden auf Port 3
  • Bei eingehenden Paket auf Port (in_port) 3 mit dem Ziel dl_dst=00:00:00:00:00:01 (dl = Data Link)
    • Aussenden auf Port 1
  • Passen die eingehenden Pakete nicht auf diese Flows, dann sende die Pakete an den Controller
mininet> dpctl dump-flows --protocols OpenFlow13
*** s1 ------------------------------------------------------------------------
OFPST_FLOW reply (OF1.3) (xid=0x2):
 cookie=0x0, duration=4921.582s, table=0, n_packets=3, n_bytes=182, priority=0 actions=CONTROLLER:65535
 cookie=0x0, duration=897.163s, table=0, n_packets=6, n_bytes=532, priority=1,in_port=3,dl_dst=00:00:00:00:00:01 actions=output:1
 cookie=0x0, duration=897.057s, table=0, n_packets=5, n_bytes=434, priority=1,in_port=1,dl_dst=00:00:00:00:00:02 actions=output:3

Abschließende Informationen

Idle Timeout

Beim Idle Timeout handelt es sich die Zeit (in Sekunden) nach der der Flow aufgrund von Inaktivität (Flow hat nicht auf eingehende Pakete gepasst, engl. „match“) entfernt wird.

0 = unendlich

Hard Timeout

Beim Hard Timeout handelt es sich die Zeit (in Sekunden) nach der der Flow trotz Aktivität entfernt wird.

0 = unendlich

Priority

Je höher die Priority, desto wichtiger ist der Eintrag. Soll heissen, passt ein Paket auf einen Flow mit der Priorität 500 und würde auch auf einen Eintrag mit der Priorität 300 passen, wird der OVS/Switch bis zu diesem Eintrag nie kommen da die Abarbeitung der Tabelle nach dem ersten Eintrag stoppt und die Aktion ausgeführt wird.

Fortgeschrittene Mininet Kommandos

Ziel dieses Artikels war es einen Überblick zu geben, hier nun noch einige fortgeschrittene Kommandos mit denen man spielen kann. Viel Spaß!

Bandbreite mit iPerf testen

mininet> iperf h1 h2
*** Iperf: testing TCP bandwidth between h1 and h2
*** Results: ['7.47 Gbits/sec', '7.47 Gbits/sec']

Webserver simulieren und von anderen Teilnehmer abfragen

mininet> h2 python -m SimpleHTTPServer 80 &
mininet> h1 wget h2
--2014-07-25 10:49:42--  http://10.0.0.2/
Connecting to 10.0.0.2:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 590 [text/html]
Saving to: ‘index.html’

     0K                                                       100% 11.7M=0s

2014-07-25 10:49:42 (11.7 MB/s) - ‘index.html’ saved [590/590]

Alle Teilnehmer sich gegenseitig pingen lassen

mininet> pingall
*** Ping: testing ping reachability
h1 -> h2 h3 h4 
h2 -> h1 h3 h4 
h3 -> h1 h2 h4 
h4 -> h1 h2 h3 
*** Results: 0% dropped (12/12 received)

Alle Teilnehmer sich gegenseitig pingen lassen (mehr Details)

mininet> pingallfull
*** Ping: testing ping reachability
h1 -> h2 h3 h4 
h2 -> h1 h3 h4 
h3 -> h1 h2 h4 
h4 -> h1 h2 h3 
*** Results: 
 h1->h2: 1/1, rtt min/avg/max/mdev 1.119/1.119/1.119/0.000 ms
 h1->h3: 1/1, rtt min/avg/max/mdev 0.713/0.713/0.713/0.000 ms
 h1->h4: 1/1, rtt min/avg/max/mdev 0.939/0.939/0.939/0.000 ms
 h2->h1: 1/1, rtt min/avg/max/mdev 0.085/0.085/0.085/0.000 ms
 h2->h3: 1/1, rtt min/avg/max/mdev 0.908/0.908/0.908/0.000 ms
 h2->h4: 1/1, rtt min/avg/max/mdev 0.868/0.868/0.868/0.000 ms
 h3->h1: 1/1, rtt min/avg/max/mdev 0.093/0.093/0.093/0.000 ms
 h3->h2: 1/1, rtt min/avg/max/mdev 0.085/0.085/0.085/0.000 ms
 h3->h4: 1/1, rtt min/avg/max/mdev 0.972/0.972/0.972/0.000 ms
 h4->h1: 1/1, rtt min/avg/max/mdev 0.094/0.094/0.094/0.000 ms
 h4->h2: 1/1, rtt min/avg/max/mdev 0.092/0.092/0.092/0.000 ms
 h4->h3: 1/1, rtt min/avg/max/mdev 0.099/0.099/0.099/0.000 ms

Zwei Teilnehmer pingen mit mehr Details

mininet> pingpairfull
h1 -> h2 
h2 -> h1 
*** Results: 
 h1->h2: 1/1, rtt min/avg/max/mdev 1.270/1.270/1.270/0.000 ms
 h2->h1: 1/1, rtt min/avg/max/mdev 0.050/0.050/0.050/0.000 ms

Informationen über den OVS anzeigen

mininet> dpctl show --protocols OpenFlow13
*** s1 ------------------------------------------------------------------------
OFPT_FEATURES_REPLY (OF1.3) (xid=0x2): dpid:0000000000000001
n_tables:254, n_buffers:256
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS
OFPT_GET_CONFIG_REPLY (OF1.3) (xid=0x4): frags=normal miss_send_len=0

Nach Abschluss der Tests mit Mininet aufräumen

Dieses Kommando erst nach Beendigung der Tests durchführen!

Löscht alle Überbleibsel der Tests. Sollte nach umfangreicheren Tests durchgeführt werden um zu vermeiden dass sich Altlasten in den nächsten Test einschleichen.

$ sudo mn -c

Relevante Dokumentation

einstieg-in-sdn-mit-mininet-vm-und-ryu-controller.1406312200.txt.gz · Zuletzt geändert: 2014/07/25 18:16 von benny

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki