Instrukcja do laboratorium 3 Rest API. Proaktywna instalacja przepływów. 1. Cel ćwiczenia Celem ćwiczenia jest zapoznanie się z Rest API kontrolera Floodlight. Podczas zajęć przedstawione zostaną metody proaktywnej instalacji przepływów w tablicy przełącznika w środowisku Mininet. 2. Uruchamianie zewnętrznego kontrolera sieci SDN W trakcie tych oraz kolejnych zajęć laboratoryjnych wykorzystywać będziemy zewnętrzny kontroler sieci SDN o nazwie Floodlight. Napisany jest on w języku Java. 2.1 Przygotowanie środowiska Przed zbudowaniem i uruchomieniem środowiska należy zainstalować potrzebne repozytoria poleceniem: $ sudo apt-get install build-essential ant maven python-dev 2.2 Pobieranie i budowanie kontrolera Proszę pobrać kontroler (version 1.2) ze strony projektu: https://github.com/floodlight/floodlight/archive/v1.2.tar.gz a następnie rozpakować go, np. poleceniem: $ tar -xf floodlight* Następnie należy przejść do rozpakowanego katalogu i zbudować kontroler ze źródeł poleceniem $ ant 2.3 Uruchomienie i testowanie zewnętrznego kontrolera Uwaga: Przed uruchomieniem kontrolera proszę zamknąć wszystkie topologie uruchomione w środowisku Mininet. W celu uruchomienia kontrolera należy w katalogu głównym kontrolera z wiersza poleceń wydać następujące polecenie: $ java -jar target/floodlight.jar Proszę zaobserwować start kontrolera. Kontroler od tej pory powinien nasłuchiwać przełączników za pomocą protokołu LLDP. Następnie (w innej konsoli) należy uruchomić środowisko Mininet z bazową topologią wskazując, że wykorzystany zostanie zewnętrzny kontroler: $ sudo mn --controller=remote,ip=<controller ip>,port=6653 Zadanie 1. Proszę przetestować działanie sieci z wykorzystaniem zewnętrznego kontrolera, np. poleceniem: mininet> h1 ping h2 1
Zadanie 2. W jaki sposób można zmienić poziom logowania przez kontroler? Proszę ustawić poziom logowania na DEBUG i zaobserwować zmiany. Po tym proszę wrócić do poziomu INFO. 3. Web GUI kontrolera Floodlight Kontroler Floodlight został wyposażony w GUI dostępne z poziomu przeglądarki komunikujące się z kontrolerem za pomocą Rest API. Pozwala ono m.in. na obserwację kontrolowanych przełączników, ich statystyk, wpisów tablic przepływów oraz na podstawowe zmiany w konfiguracji kontrolera oraz przełączników (np. dodawanie przepływów). Dostęp do GUI można uzyskać wchodząc na stronę: http://<controller-ip>:8080/ui/index.html Zadanie 3. Proszę sprawdzić zawartość tablicy przepływów przełącznika z poziomu Web GUI (bez jakiegokolwiek ruchu pomiędzy wirtualnymi hostami). Zadanie 4. Proszę powtórzyć zadanie 3, tym razem wcześniej uruchamiając ping pomiędzy h1 a h2. Następnie proszę zatrzymać polecenie ping i jeszcze raz sprawdzić tablicę przepływów. Z czego wynikają zmiany? 4. Proaktywna instalacja przepływów. W dalszej części laboratorium zastosowany zostanie proaktywny tryb instalacji wszystkich przepływów w przełączniku. W trybie tym, w przeciwieństwie do trybu reaktywnego, przepływy instalowane są zanim jakikolwiek pakiet należący do danego przepływu pojawi się w sieci. W ten sposób można tworzyć m.in. proste reguły ACL, firewalli czy też bardzo proste funkcje load-balancera (np. wykorzystując tablice grupowe). 4.1 Wyłącznie modułu Forwarding kontrolera Floodlight. Za instalowanie przepływów w trybie reaktywnym przez kontroler Floodlight odpowiedzialny jest moduł net.floodlightcontroller.forwarding.forwarding. W celu deaktywacji tego modułu należy usunąć odpowiednią linijkę w pliku src/main/resources/floodlightdefault.properties Uwaga: Przed edycją pliku proszę wykonać jego kopię zapasową! Zadanie 5. Po edycji pliku proszę przetestować łączność pomiędzy h1 a h2 (należy wcześniej wykonać restart kontrolera). Wszelkie uwagi należy skierować do prowadzącego. 4.2 Ręczna instalacja przepływów W celu ręcznej instalacji przepływów w przełącznikach OpenFlow można wykorzystać Rest API wystawiane przez kontroler. Kontroler obsługuje wiele URI tym samym pozwalając na komunikację z zewnętrznymi aplikacjami poprzez interfejs północny. Dokładną listę obsługiwanych adresów oraz ich funkcjonalność można znaleźć na stronie projektu 1. Proszę doinstalować aplikację curl poleceniami: $ sudo apt-get update $ sudo apt-get install curl 1 https://floodlight.atlassian.net/wiki/display/floodlightcontroller/static+entry+pusher+api 2
Podczas zajęć wykorzystywana będzie aplikacja curl. Możliwe jest także dodawanie przepływów za pomocą wtyczek RESTowych do przeglądarek, np. Advanced REST Client, Postman. W celu wysłania polecenia utworzenia nowego wpisu w tablicy przepływów przełącznika należy wysłać odpowiednio sformatowany JSONowy ciąg znaków na odpowiedni adres URL, np. $ curl -X POST -d '{"switch":"00:00:00:00:00:00:00:01", "name":"flow1", "priority":"32768", "in_port":"1","active":"true", "actions":"output=2"}' http://<controller_ip>:8080/wm/staticflowpusher/json Polecenie to wykonuje metodę POST, w przełączniku o DPID = 00:00:00:00:00:00:00:01 instalowany zostaje przepływ o nazwie "flow1", z priorytetem o wartości 32768. Przepływ ten wszystkie pakiety z portu nr 1 przekierowywuje na port nr 2 (akcja: output=2). Uwaga: Nr interfejsów (OpenFlow) nadawane są przez przełącznik, niekoniecznie są równoznaczne z numerami interfejsów w sprzęcie. Szczególnie zaobserwowane zostanie to podczas konfiguracji przełączników firmy Juniper. Zadanie 6. W jaki sposób sprawdzić DPID przełącznika Open vswitch? Zadanie 7. Proszę dodać odpowiedni wpis do tablicy przełącznika, aby możliwa była komunikacja pomiędzy h1 a h2. 4.3 Przydatne URI W celu wylistowania zainstalowanych przepływów w danym przełączniku można wysłać do kontrolera następujące zapytanie (z odpowiednim DPID): curl http://<controller_ip>:8080/wm/staticflowpusher/list/00:00:00:00:00:00:00:0 1/json Listowanie wszystkich przepływów, wszystkich przełączników podłączonych do danego kontrolera dokonuje się poleceniem: curl http://<controller_ip>:8080/wm/staticflowpusher/list/all/json Kasowanie wszystkich wpisów można wykonać poleceniami (odpowiednio dla jednego oraz wszystkich przełączników): curl http://<controller_ip>:8080/wm/staticflowpusher/clear/00:00:00:00:00:00:00: 01/json curl http://<controller_ip>:8080/wm/staticflowpusher/clear/all/json Kasowanie pojedynczego wpisu: curl -X DELETE -d '{"name":"flow1"}' http://<controller_ip>:8080/wm/staticflowpusher/json Zadanie 8. Proszę za pomocą tylko jednego wpisu zapewnić komunikację pomiędzy h1 a h2 w topologii minimalnej środowiska Mininet. 4.4 Operacje na własnej topologii. Korzystając z instrukcji do laboratorium nr 1 proszę stworzyć topologię jak na rysunku 1. 3
S4 Host h1 S1 S3 Host h3 S2 Rysunek 1. Topologia wykorzystywana podczas ćwiczeń Zadanie 9. Proszę dodać odpowiednie przepływy a następnie przetestować działanie sieci w następujących przepadkach: a) Zapytanie ICMP z hosta h1 do h2 wędruje kolejno przez S1-S2-S3 a odpowiedź wraca S3-S4-S1 b) Cały ruch UDP z hosta h1 do h2 wędruje przez S1-S3 c) Cały ruch TCP pomiędzy h1 a h2 przechodzi przez S1-S2-S4-S3 d) Ruch TCP z h1 do h2 na porcie 80, na adres IP hosta h2 przechodzi ścieżką S1-S4-S2-S3 Uwaga: Pomocne może być wykorzystanie terminali xterms odpowiednich węzłów (serwer HTTP dla ruchu TCP, iperf dla ruchu UDP) oraz programu Wireshark/tcpdump uruchomionego na odpowiednich interfejsach przełączników lub hostów. 4
4.5 Wykorzystanie języka Python do obsługi Rest API Powyższe przykłady ilustrowały wykorzystanie programu curl do wysyłania poleceń do kontrolera. Możliwe jest wykorzystanie dowolnego języka programowania w celu komunikacji z kontrolerem na interfejsie północnym. Poniżej prezentowany jest przykład z dokumentacji kontrolera ilustrujący możliwość dodawania przepływów z wykorzystaniem skryptu w języku Python. import httplib import json class StaticEntryPusher(object): def init (self, server): self.server = server def get(self, data): ret = self.rest_call({}, 'GET') return json.loads(ret[2]) def set(self, data): ret = self.rest_call(data, 'POST') return ret[0] == 200 def remove(self, objtype, data): ret = self.rest_call(data, 'DELETE') return ret[0] == 200 def rest_call(self, data, action): path = '/wm/staticflowpusher/json' headers = { 'Content-type': 'application/json', 'Accept': 'application/json', } body = json.dumps(data) conn = httplib.httpconnection(self.server, 8080) conn.request(action, path, body, headers) response = conn.getresponse() ret = (response.status, response.reason, response.read()) print ret conn.close() return ret pusher = StaticEntryPusher('<insert_controller_ip>') flow1 = { 'switch':"00:00:00:00:00:00:00:01", "name":"flow1", "cookie":"0", "priority":"32768", "in_port":"1", "active":"true", 5
"actions":"output=2" } flow2 = { 'switch':"00:00:00:00:00:00:00:01", "name":"flow2", "cookie":"0", "priority":"32768", "in_port":"2", "active":"true", "actions":"output=1" } pusher.set(flow1) pusher.set(flow2) Zadanie 10. Modyfikując odpowiednio powyższy kod proszę wysłać polecenia utworzenia przepływów flow1 oraz flow2. Zadanie 11. Proszę tak zmodyfikować kod w Pythonie, aby ustawić hard timeout obu przepływów na wartość 10 sekund. 6