Język P4 i programowanie urządzeń sieciowych

Krzysztof Kempiński
Jun 8 · 18 min read

W ramach podcastu “Porozmawiajmy o IT” miałem okazję porozmawiać z Pawłem Parolem o języku P4 i programowaniu urządzeń sieciowych.

Posłuchaj naszej rozmowy w wersji audio 🎧 👇

Cześć! Mój dzisiejszy gość to absolwent telekomunikacji na Politechnice Warszawskiej, wieloletni pracownik Orange Polska związany z sieciami SDN, podejściem DevOps, cloud i edge computing, obecnie na stanowisku senior network engineer of CodiLime, gdzie koordynuje pracami R&D, zarządza zespołami budującymi innowacyjne rozwiązania sieciowe w obszarze SDN, NFV i dzieli się swoją wiedzą. Moim i Waszym gościem jest Paweł Parol.

Cześć, Pawle! Bardzo miło mi gościć Cię w podcaście.

Cześć! Witam serdecznie!

Z Pawłem będę dzisiaj rozmawiał o trochę egzotycznym, dosyć specyficznym języku programowania, jakim jest P4 i w ogólności o programowaniu urządzeń sieciowych.

Pawle, chciałbym Cię zapytać, zresztą tak jak czynię ze wszystkimi swoimi gośćmi, czy słuchasz podcastów? Jeśli tak, to może masz jakieś audycje do zarekomendowania?

Mówiąc szczerze, rzadko. Zdarzało mi się wprawdzie okazjonalnie, ale raczej nie mam takiego zwyczaju. Natomiast ja bardzo chętnie na przykład oglądam przeróżne techniczne materiały na YouTubie, takie jak TechToki, webinaria czy nagrania z konferencji albo jakichś innych eventów. Także raczej tak to u mnie wygląda.

Dobrze, to przejdźmy już do tej części właściwej. Porozmawiajmy o języku P4. To jest język, który wywodzi się, czy właściwie jego nazwa pochodzi, od czterech liter p występujących w pełnej nazwie, czyli Programming Protocol-Independent Packet Processors, sporo tych słów. On powstał całkiem niedawno, około roku 2014. Taka unowocześniona wersja, unowocześniony standard to jest rok 2016–2017. Więc można powiedzieć, że jak na standardy nawet panujące w IT, to stosunkowo świeżynka jest. Opowiedz proszę o tym, skąd się ten język wziął, kto go stworzył, jakim celom miał on pierwotnie służyć.

Tak, to jest wciąż dość świeża technologia, można powiedzieć. Sama koncepcja języka została po raz pierwszy przedstawiona w publikacji z 2014 roku, której tytuł zresztą wymieniłeś. Ja nie podejmę próby przetłumaczenia tego tytułu jeden do jednego na Polski, bo to mogłoby zabrzmieć trochę sztucznie, natomiast mam nadzieję, że w trakcie naszej rozmowy uda mi się nieco rozjaśnić, o co tutaj w ogóle chodzi. Sama nazwa P4 to jest, tak jak sam powiedziałeś zresztą, skrót od pierwszych liter wyrazów w tytule tego artykułu. Jego autorami są przedstawiciele świata akademickiego oraz dużych firm technologicznych, głównie z Kalifornii.

A mówię o tym dlatego, żeby zwrócić uwagę, że to była dość ważna publikacja. Nie był to jeden z wielu artykułów. Mówiąc niezwykle skrótowo, istotą tej pracy jest prezentacja pewnego użytecznego narzędzia, które pozwala na programowanie urządzeń sieciowych. Tym narzędziem jest właśnie język P4.

Powiedziałbyś szerzej na temat twórców? Oczywiście to się trochę zmieniało, mówiliśmy o tym unowocześnionym standardzie, pewnie wiele firm przyłożyło się do powstania języka P4. Ale kogo wymieniłbyś jako podstawowego twórcę czy może zespół osób, firm, które się przyłożyły najbardziej do powstania tego języka?

To były osoby ze środowiska uniwersyteckiego, głównie mam na myśli Uniwersytet Stanforda. Tam był zespół profesora Nicka McKeowna, który wcześniej zajmował się szeregiem projektów związanych z SDN-ami. Jego doktorantem był między innymi Martin Casado i on stworzył podwaliny pod protokół, który się nazywał OpenFlow. A poza tym inne osoby z tak zwanego Big Techu, ja nie pamiętam dokładnie nazwisk, ale to były osoby bodajże z Microsoft, chyba ktoś z Google. Tak więc tego typu osoby.

Dobrze, to znamy mniej więcej historię języka P4 i nie jest to język szerokiego, ogólnego przeznaczenia, jak chociażby Java czy C#. Jest to język domenowy, o tym jeszcze będziemy dzisiaj rozmawiać. Chcę Cię zapytać, skąd wzięła się koncepcja tego języka, na czym ta koncepcja w ogóle polega i na jakie zapotrzebowanie ten język odpowiada?

Aby to zrozumieć, należy najpierw uświadomić sobie kilka podstawowych kwestii dotyczących większości urządzeń używanych dzisiaj w sieciach, takich jak routery, switche, firewalle. One mają oczywiście różną charakterystykę funkcjonalną, ale to, co je łączy, to pewien wysokopoziomowy koncept architektoniczny. Ogólnie każde z takich urządzeń ma w środku jakiś system operacyjny, który nadzoruje działanie wszystkich układów wewnątrz. Zwykle to jest jakaś dystrybucja Linuxa bądź Unixa i w user space tego systemu uruchomiony jest tak zwany control plane.

To jest taka aplikacja, albo zbiór aplikacji, które decydują, jak ma działać data plane urządzenia, czyli ta jego logiczna część, której zadaniem jest przetwarzanie w odpowiedni sposób napływających do urządzenia pakietów. Ale żeby to było w ogóle możliwe, to w urządzeniu zamontowany jest specjalny chipset, który fizycznie realizuje wykonywanie operacji na pakietach. To jest de facto takie serce całego urządzenia, patrząc z perspektywy funkcji sieciowych, które on oferuje.

Teraz kluczowa rzecz, chipset, o którym tutaj mówimy, to jest jednostka o pewnym z góry ustalonym zbiorze funkcjonalności. To oznacza, że gdybyśmy chcieli nasze urządzenie doposażyć na przykład w jakąś nową funkcjonalność, której chipset po prostu nie wspiera, to mamy spory problem. Możemy oczywiście, i to byłaby naturalna droga, zwrócić się z prośbą do firmy, która ten chipset wyprodukowała, żeby tę nową funkcjonalność, która jest nam potrzebna, w nim zaimplementować, ale musimy być wtedy przygotowani, że najprawdopodobniej dostaniemy taką odpowiedź, że ok, to jest możliwe, ale niestety to trochę potrwa.

Zła informacja jest taka, że mówimy tu o czasie rzędu kilku lub nawet kilkunastu miesięcy. A jest tak dlatego, że zrobienie całego redesignu układu może być w ogólności zadaniem całkiem nie trywialnym i cały taki proces może wymagać sporo czasu. Widzimy, że czekanie tak długo może być dla nas jako dostawców urządzenia zwyczajnie nieopłacalne. Biorąc pod uwagę uwarunkowania biznesowe czy z jakichś innych powodów. W przypadku standardowego podejścia do budowy urządzeń sieciowych, można w pewnym uproszczeniu powiedzieć, że wszystko kręci się tak naprawdę wokół tego chipsetu i jego możliwości. Ten paradygmat nosi nazwę bottom-up, czyli od dołu do góry. On pokazuje pewien logiczny kierunek budowy naszego urządzenia.

Tymczasem w przypadku innych obszarów IT mamy do czynienia z zupełnie innym podejściem, które określa się mianem top-down, czyli z góry na dół. To z kolei polega na tym, że niejako arbitralnie określamy funkcjonalności jakiejś aplikacji, już na samym starcie. Potem opisujemy ją za pomocą domenowego języka programowania. Następnie kompilujemy kod, po czym jest on wykonywany przez tak zwany domenowy procesor.

O co chodzi z tą domenowością? Tym terminem określamy po prostu główne zastosowanie danego procesora. Najpopularniejszym przykładem będzie oczywiście CPU, czyli jednostki do ogólnych zastosowań obliczeniowych. Ale są także procesory o nieco bardziej specyficznych zastosowaniach, jak choćby GPU, których architektura jest dobrze zoptymalizowana do renderowania grafiki, czy na przykład procesory sygnałowe, DSP, które oferują odpowiednią wydajność w procesie przetwarzania różnych sygnałów w czasie rzeczywistym. Dla każdego z tych przypadków dysponujemy zbiorem pewnych języków domenowych, czyli takich języków programowania czy bibliotek, dzięki którym możemy tworzyć kod dla aplikacji, które są potem wykonywane na tych jednostkach.

Dla przykładu, dla CPU będzie to cała gama języków, które dobrze znamy typu C++, Java, Python, Golang i tak dalej. W przypadku GPU będzie to na przykład OpenGL albo DirectX, a w przypadku wspomnianych procesorów DSP, może być to na przykład cały framework MATLABa. Natomiast to, z czego warto sobie zdać sprawę i co dotyczy w zasadzie każdego z wymienionych tu obszarów to jest fakt, że mamy tu do czynienia z takim sposobem tworzenia aplikacji, w którym procesor zasadniczo nie ogranicza ani nie narzuca pewnego potencjału funkcjonalnego aplikacji. I to jest właśnie istota paradygmatu top-down.

Teraz automatycznie powstaje pytanie, jak można by w takim razie zaadoptować to podejście do urządzeń sieciowych, gdzie jak pokazywałem, bazujemy na zupełnie innym paradygmacie. Żeby to zrobić, potrzebujemy dwóch rzeczy. Po pierwsze, musimy dysponować innymi chipsetami niż dotychczas. Te nowe chipy muszą być programowalne. A po drugie, musimy dysponować frameworkiem, który pozwoli te chipy odpowiednio zaprogramować. I tutaj wreszcie dochodzimy do języka P4, który właśnie do tego nam służy.

Po pierwsze, musimy dysponować innymi chipsetami niż dotychczas. Te nowe chipy muszą być programowalne. A po drugie, musimy dysponować frameworkiem, który pozwoli te chipy odpowiednio zaprogramować. I tutaj wreszcie dochodzimy do języka P4, który właśnie do tego nam służy.

Powiedzmy może nieco więcej na temat designu i architektury tego języka. Na czym polega to programowanie data plane’u, o którym powiedziałeś, przy użyciu P4?

Zacznę może od tego, że aby w ogóle móc tego języka efektywnie używać, to trzeba mieć pewne wyobrażenie o tym, jak działają sieci i jak wygląda pewien proces komunikacji między węzłami w sieciach. Takim podstawowym modelem odniesienia czy też pewną abstrakcją, której powszechnie używa się do opisu tych kwestii, jest tak zwany model OSI. To jest taki model, który wyodrębnia w systemach sieciowych pewne warstwy. Jeżeli ktoś zna się trochę na sieciach, to z pewnością wie, o czym mówię i zna to pojęcie, ponieważ to jest w zasadzie wiedza podstawowa. Każda z tych warstw w modelu OSI ma pewne swoje specyficzne znaczenie i specyficzne zadania w ramach obsługi całego procesu komunikacji między dwoma węzłami w sieci.

Żeby ta komunikacja na poszczególnych warstwach odbywała się efektywnie, dla każdej takiej warstwy określony jest zestaw tak zwanych protokołów, które służą do tego, żeby wymiana informacji właściwych dla danej warstwy odbywała się w sposób zestandaryzowany. Wymienię może kilka nazw, które myślę, że każdemu słuchaczowi obiły się kiedyś o uszy. Nawet jeżeli ktoś nie zajmuje się sieciami na co dzień, to na pewno słyszał takie pojęcia, jak choćby Ethernet, IP, TCP, UDP, DHCP i tak dalej. To są właśnie przykłady popularnych protokołów komunikacyjnych.

Pakiety, które przesyłane są w sieciach w postaci ciągu bitów de facto, mają swoją pewną strukturę, w której wyodrębnić można między innymi zestaw tak zwanych nagłówków. A każdy pojedynczy nagłówek, to taki fragment tego ciągu bitów, który zawiera pewne charakterystyczne informacje dla danego protokołu. Dla przykładu, pakiet może zawierać nagłówek Ethernetowy, dalej nagłówek protokołu IP, nagłówek protokołu TCP i tak dalej.

Natomiast samą istotą procesu przetwarzania pakietów w jakimkolwiek urządzeniu sieciowym jest odczytywanie informacji zawartych w nagłówkach i wykonywanie na tej podstawie akcji, jak modyfikacja wartości poszczególnych pól w danym nagłówku czy przekierowanie pakietu na wskazany interfejs fizyczny. To się zwykle odbywa w postaci tak zwanego pipeline’u, czyli pewnej logicznej sekwencji tablic, które po kolei odwiedza pakiet. A każda taka tablica ma zwykle jakąś swoją charakterystyczną rolę, na przykład może się zajmować tylko nagłówkami określonego typu, czyli ma jasno zdefiniowane, jakie dokładnie pola w nagłówkach ma oglądać i jakie na tej podstawie decyzje podejmować.

W urządzeniach sieciowych zbudowanych na bazie tradycyjnego podejścia, cały ten schemat przetwarzania jest z góry ustalony na poziomie chipsetu i nie można go zmienić. Natomiast gdy użyjemy chipów programowalnych, to za pomocą języka P4 możemy cały proces przetwarzania zdefiniować po swojemu. Co to oznacza? To oznacza, że my decydujemy, ile ma być tablic i jakie one mają być. Decydujemy, jaka ma być kolejność ich odwiedzania przez pakiety, decydujemy, jakie nagłówki, jakie konkretne pola w nagłówkach będziemy analizować w poszczególnych tablicach. Sami też określamy wszystkie dostępne akcje do wykonania w każdej tablicy. Oczywiście też definiujemy szczegółowo mechanikę działania każdej akcji. To jest w zasadzie wszystko przedmiotem implementacji. I tu właśnie tkwi największa siła P4, bo nam chodzi o tę elastyczność.

Co więcej, warte podkreślenia jest to, że P4 nie określa żadnego predefiniowanego zbioru nagłówków, na których możemy operować. Struktura wszystkich nagłówków, nawet tych, które się odnoszą do popularnych protokołów musi być explicite zdefiniowana przez programistę w każdym programie P4. To się odbywa w takim specjalnym bloku kodu, który określany jest mianem parsera. To założenie języka ma ciekawy wymiar użytkowy, ponieważ dzięki temu, możemy za pomocą P4 testować nawet, jak zachowują się zupełnie customowe protokoły, które zresztą sami możemy sobie projektować.

A jak już jesteśmy przy samym języku, to wszystkie te zagadnienia, o których przed momentem wspomniałem, mówiąc tutaj o swobodzie w definiowaniu zachowania całego data plane’u, czyli tablic, akcji, kolejności wyzwalania pewnych rzeczy, to wszystkie te aspekty w języku P4 odwzorowane są za pomocą słów kluczowych, takich jak table, action, control, parser, apply. W tej nowszej wersji języka, która nosi nazwę P4–16, mamy bodajże około czterdziestu takich słów kluczowych. Używając tych słów w kodzie po prostu wskazujemy, jakie struktury czy jakie elementy będziemy w danej chwili definiować. Tak to wygląda.

Ok, rozumiem. To jest faktycznie dosyć szeroki wachlarz różnych możliwości, o których powiedziałeś. Wiadomo, że one muszą być wykorzystywane na jakimś sprzęcie, na jakichś urządzeniach. Mówiłeś, że urządzenia sieciowe są naturalnym targetem do uruchamiania programów w P4. Chcę Cię zapytać, jakie urządzenia sieciowe? Dowolne czy może jest jakiś zakres tych urządzeń? Czy język P4 sięga też dalej, czy wychodzi poza urządzenia sieciowe, czy to jest jego jedyna domena?

Najkrócej można by odpowiedzieć, że my możemy przy pomocy P4 programować w zasadzie wszystkie urządzenia, które zawierają programowalne chipsety wspierające tę technologię. Natomiast w praktyce, można wyodrębnić trzy grupy takich urządzeń, a w zasadzie trzy grupy tak zwanych targetów. W nomenklaturze P4 urządzenia, na które piszemy kod, nazywamy targetami.

Pierwszą grupą będą tak zwane urządzenia wieloportowe. Chodzi o takie urządzenia, które instaluje się zwykle w centrach danych, w serwerowniach bądź obiektach operatorów telekomunikacyjnych. Umownie, w ramach pewnej konwencji, nazywamy je ogólnie switchami. Przy czym należy od razu zaznaczyć, że ich funkcjonalność może być znacznie szersza, niż tradycyjnych switchy L2.

Klasyczne urządzenia sieciowe, wszystkie te, które są oparte o chipsety o tej ustalonej funkcjonalności, czyli budowane według tradycyjnego podejścia, mają już niejako z definicji wpisaną jakąś specjalizację. Na przykład, jeżeli urządzenie jest routerem, to będzie realizować routing, bo do takiej pracy zostało zaprojektowane i zoptymalizowane. Jeżeli urządzenie jest switchem L2, to będzie działać jako przełącznik. Jeżeli jest firewallem, to będzie robiło firewalling. Możemy wymieniać dalej.

Natomiast w przypadku urządzeń wspierających P4, ten umowny switch wieloportowy raz będzie routerem, innym razem będzie zoptymalizowany do działania jako switch L2, jak go przeprogramujemy. Jeszcze innym razem będzie firewallem lub urządzeniem BNG albo DPI-em albo w ogóle mieszanką kilku funkcjonalności na raz.

Natomiast w przypadku urządzeń wspierających P4, ten umowny switch wieloportowy raz będzie routerem, innym razem będzie zoptymalizowany do działania jako switch L2, jak go przeprogramujemy. Jeszcze innym razem będzie firewallem lub urządzeniem BNG albo DPI-em albo w ogóle mieszanką kilku funkcjonalności na raz.

Dlaczego tak jest? Dlatego, że my to urządzenie możemy wielokrotnie reprogramować przy użyciu języka P4, czyli tworzyć zupełnie arbitralną strukturę jego data plane’u, która raz będzie miała jakiś określony przez nas design, czyli wszystkie te tablice, akcje, jakie chcemy na daną chwilę. Innym razem, po przeprogramowaniu, będzie to inny design w zależności od tego, jakie mamy na dany czas potrzeby. I to jest jedna, taka duża grupa urządzeń.

Druga grupa targetów, o których warto wspomnieć, to są tak zwane SmartNICi. To jest rodzaj takich inteligentnych kart sieciowych, które można zamontować na przykład w serwerze. Nie wchodząc już w jakieś duże zawiłości techniczne, to są po prostu takie karty, które oferują dużo większe możliwości niż standardowe karty sieciowe, ponieważ można w ogólności uruchomić na nich różne funkcje sieciowe. Obecnie na rynku dostępnych jest już kilka kart, które oferują także wsparcie dla technologii P4, co oznacza, że możemy po prostu programować je przy użyciu P4.

Robiliśmy jakiś czas temu nawet taki przegląd rozwiązań dla tego segmentu rynku. Wyniki opisaliśmy na naszym blogu technologicznym. Gdyby ktoś chciał pogłębić ten temat, to serdecznie zapraszam do odwiedzenia oficjalnej witryny CodiLime i zapoznania się z tym blog postem.

Jest jeszcze trzecia grupa rozwiązań wspierających P4, którą bym wyodrębnił. W zasadzie to nie są urządzenia fizyczne, tylko switche software’owe, czyli takie wirtualne urządzenia sieciowe, do których możemy podłączać wirtualne maszyny czy kontenery. Także w tej grupie istnieją takie, które możemy programować przy użyciu języka P4.

Przy okazji myślę, że warto jeszcze wspomnieć o jednej, bardzo istotnej kwestii, która związana jest z urządzeniami P4. Standard P4–16, czyli ta nowsza wersja języka, wprowadza takie pojęcie, jak model architektury. O co tutaj chodzi? Każde urządzenie w ramach architektury swojego data plane’u może mieć różne bloki funkcjonalne. Tak naprawdę nawet nie wszystkie z nich muszą być programowalne w P4. Zachowania niektórych bloków w tym procesie przetwarzania pakietów mogą być po prostu ustalone z góry i wtedy to nie podlega żadnym modyfikacjom ze strony programisty.

To jest w dalszym ciągu akceptowalne, ponieważ nie wszystkie bloki w urządzeniu muszą być programowalne, aby można było mówić, że ono wspiera P4. Wystarczy, aby istniały takie, które programować się da. Ale programista musi o tym wiedzieć, musi dysponować pewnym widokiem, czyli jak wygląda wysokopoziomowy schemat data plane’u targetu. Ile tam jest łącznie wszystkich bloków funkcjonalnych, które są programowalne, a które nie są oraz jakie funkcje pełnią te, których nie można programować.

Pewną abstrakcją, która dostarcza tych informacji, jest tak zwany model architektury P4. To jest zadanie producenta urządzenia, który musi zadeklarować, z którym modelem jego rozwiązanie jest zgodne. Ponieważ istnieją zarówno standardowe czy quasi standardowe modele i takie zupełnie własnościowe, czyli projektowane przez producentów.

Rozumiem. Powiedziałeś o programiście, jestem ciekaw, jak się programuje w takim języku na co dzień. Jakie narzędzia programiści mają do dyspozycji? Czy są może dedykowane IDE, coś co by ułatwiało tworzenie kodu w P4?

Standardowy proces tworzenia programu P4 można opisać następująco. Po pierwsze, musimy wiedzieć, co jest naszym targetem. Czy to jest switch, czy to jest SmartNIC, a może jeszcze coś innego? Od razu sprawdzamy ten model architektury, o którym wspomniałem, który ten target wspiera. Jest to naturalnie potrzebne, żeby stwierdzić, jakie dokładnie bloki funkcjonalne naszego data plane’u możemy oprogramować, jakie mamy możliwości, jakie ograniczenia.

Kiedy już to wszystko wiemy, wtedy dopiero przystępujemy do pisania kodu w języku P4. Standardowo można to robić w dowolnie wybranym przez siebie edytorze. Najlepiej w takim, który posiada wsparcie dla języka P4, czyli potrafi rozpoznać jego składnię, słowa kluczowe dla większej wygody pisania kodu. Jest kilka darmowych edytorów, które takie wsparcie dla P4 oferują. Kiedy nasz kod jest już gotowy, należy go skompilować. Kompilator powinien być dostarczony przez producenta urządzenia, na które piszemy nasz program. Jeśli kompilacja zakończy się sukcesem, jej produkty należy wgrać na urządzenie docelowe. Używam liczby mnogiej, ponieważ w szczególności może to być więcej niż jeden plik. Na przykład jakiś plik binarny plus opcjonalnie dodatkowe pliki konfiguracyjne. Ta sekwencja kroków, o której tutaj powiedziałem, jest taką ogólną procedurą tworzenia programów w języku P4.

Natomiast skoro zapytałeś o rozwiązania typu IDE, to z tego, co wiem, niektórzy dostawcy urządzeń wspierających P4 rzeczywiście oferują taki software typu studio, który zawiera dedykowany edytor, zintegrowany builder czy kompilator, czy też inne dodatkowe toole. Niezależnie od tego, jakich narzędzi będziemy używać, chodzi nam o to, aby napisać taki kod, który da się skompilować i aby odpowiednie pliki wykonywalne osadzić na urządzeniu docelowym. To w zasadzie tyle od strony formalnej. Natomiast czy nasz program działa zgodnie z naszym oczekiwaniem pod względem funkcjonalnym, to już jest zupełnie inne pytanie. Tego się dowiadujemy w fazie testów.

Niezależnie od tego, jakich narzędzi będziemy używać, chodzi nam o to, aby napisać taki kod, który da się skompilować i aby odpowiednie pliki wykonywalne osadzić na urządzeniu docelowym. To w zasadzie tyle od strony formalnej. Natomiast czy nasz program działa zgodnie z naszym oczekiwaniem pod względem funkcjonalnym, to już jest zupełnie inne pytanie. Tego się dowiadujemy w fazie testów.

Przejdźmy może do testowania, bo najczęściej w nowoczesnym software developemencie jest tak, że jeśli mówimy o programowaniu, to mówimy też o testowaniu naszych rozwiązań. Jestem ciekaw, jak to wygląda w przypadku P4, czy możemy na etapie pisania kodu w jakiś sposób przeprowadzić jego testy? Z tego co zrozumiałem, wydaje mi się, że może być niezbędne uruchomienie tego napisanego i skompilowanego kodu na urządzeniu fizycznym, żeby sprawdzić tak na sto procent poprawność napisanego przez nas oprogramowania. Czy może tutaj się mylę i są jakieś rozwiązania wspomagające testowanie już na etapie pisania kodu?

Odpowiedź brzmi — to jest jedna z ulubionych odpowiedzi ludzi z IT, zresztą chyba nie tylko — to zależy. Znowu wraca kwestia tak zwanych modeli architektury, które wspierają urządzenia. Jest na przykład taki pseudo standardowy model, który nazywa się V1 model i jeśli jakieś fizyczne urządzenie sieciowe, na które piszemy nasz program w P4 wspiera ten model, to możemy sobie bardzo ułatwić wtedy fazę testowania. A dzieje się tak dlatego, że ten model jest wspierany przez takiego software’owego switcha, który się nazywa BMv2. To jest bardzo popularne rozwiązanie do budowania testowych setupów P4. Wtedy w praktyce możemy zastosować takie podejście, że najpierw testujemy nasz program na tym software’owym switchu BMv2, a dopiero w fazie końcowej już na fizycznym urządzeniu.

Ale to jest taki specyficzny przypadek, ogólnie nie zawsze jest to możliwe. W niektórych przypadkach może się okazać, że trzeba będzie testować od początku na fizycznym sprzęcie. A sam proces testowania sprowadza się do tego, że my musimy ocenić, jak zachowuje się zaprojektowany przez nas mechanizm przetwarzania pakietów tak naprawdę.

Jak pamiętamy, mam nadzieję, składają się na niego przede wszystkim stworzone przez nas tablice i tak zwane akcje, które są w nich wyzwalane na rzecz tych trafiających do tych tablic pakietów. Tablice są na początku zupełnie puste, więc pierwsze, co musimy zrobić, to utworzyć w nich odpowiednie wpisy. Każdy taki wpis mówi nam, jaka konkretnie kombinacja wartości pól w nagłówkach pakietów nas interesuje, a ponadto, którą ze zdefiniowanych przez nas operacji mamy na takim pakiecie zrealizować oraz z jakimi parametrami dokładnie. Mówiąc obrazowo, musimy zasilić te tablice odpowiednimi danymi, żeby one wiedziały, co dokładnie zrobić z konkretnymi już pakietami, kiedy one już do nich napłyną.

Ten proces się nazywa populacją tablic danymi. Ona się może odbywać w różnoraki sposób. Możemy na przykład zrobić jakiś statyczny plik konfiguracyjny, który będzie za to odpowiadał albo możemy napisać zewnętrzny moduł software’owy, który będzie dynamicznie dodawał bądź zmieniał wpisy w tablicach.

Kolejna istotna kwestia to same pakiety, bo należy pamiętać, że musimy je jakoś wygenerować. I tutaj opcji też jest wiele. Ogólnie można korzystać z software’owych bądź fizycznych nawet generatorów ruchu, jeśli ktoś ma taką możliwość. Ewentualnie generować pakiety przy pomocy dedykowanych bibliotek programistycznych. Na przykład stosunkowo łatwo napisać takie skryty w Pythonie.

Jeżeli natomiast cały nasz setup jest stricte software’owy, to może się okazać, że dla naszych konkretnych przypadków testowych zupełnie wystarczający będzie jakiś emulator topologii sieciowych typu Mininet, który jest takim wygodnym narzędziem do testowania różnych elementów sieciowych w środowisku wirtualnym czy software’owym po prostu. Tak więc wszystko tutaj sprowadza się do określenia, jakie są nasze potrzeby i jakie są możliwości.

Ok, rozumiem. Chciałbym Cię jeszcze dopytać trochę o zastosowania i cele używania P4. Wyobrażam sobie, że jeśli mamy te różne protokoły z modelu OSI, które przywołałeś, to one są już jakoś ustalone, w sensie funkcjonują tam zasady panujące nieraz już od dziesięcioleci. Po co chcielibyśmy programowo w to jeszcze ingerować, skoro moglibyśmy tę implementację zawrzeć na stałe w krzemie? Szersze pytanie brzmi, jakie są ogólnie zastosowania P4? Czy to jest tylko research i developement, czy może faktycznie jakieś produkcyjne rozwiązania są na szerszą skalę tworzone?

Zastosowania mogą być przeróżne. Pierwszym przykładem może być wykorzystanie P4 do optymalizacji działania sieci w data center. Tutaj mam na myśli tak zwany Leaf-spine fabric, to jest taka specyficzna topologia, która składa się z dwóch grup switchy o pewnej krotności i rozpiętych między nimi połączeniach fizycznych. Jest to bardzo popularne rozwiązanie w dzisiejszych centrach danych. Taki szkielet sieciowy można zbudować na przykład na bazie tradycyjnych urządzeń dostępnych na rynku, które mają z zasady jakiś zestaw dostępnych funkcjonalności. Potem te funkcjonalności wykorzystujemy, aby zrealizować całą sieciową inżynierię ruchową w naszym data center, którą sobie wcześniej określiliśmy czy zaprojektowaliśmy.

W wielu przypadkach może się okazać, że do obsługi wszystkich wzorców czy schematów ruchowych, które będą w praktyce występować w tym naszym data center, potrzebne jest znacznie mniej albo trochę mniej funkcji niż oferują nam urządzenia sieciowe, które wcześniej kupiliśmy. Sporego wachlarza funkcji możemy w ogóle nie potrzebować, mimo że za to tak naprawdę zapłaciliśmy. Tutaj pojawia się opcja wykorzystania P4. Zamiast tego można użyć urządzeń z programowalnymi chipami, w których za pomocą języka P4 zaprojektujemy takie działanie data plane’u, które będzie dobrze zoptymalizowane do naszych bieżących potrzeb. Przetwarzanie pakietów będzie wówczas oparte tylko na tych mechanizmach, które są nam naprawdę potrzebne.

Sporego wachlarza funkcji możemy w ogóle nie potrzebować, mimo że za to tak naprawdę zapłaciliśmy. Tutaj pojawia się opcja wykorzystania P4. Zamiast tego można użyć urządzeń z programowalnymi chipami, w których za pomocą języka P4 zaprojektujemy takie działanie data plane’u, które będzie dobrze zoptymalizowane do naszych bieżących potrzeb. Przetwarzanie pakietów będzie wówczas oparte tylko na tych mechanizmach, które są nam naprawdę potrzebne.

Ale to jest tylko jeden aspekt, spójrzmy na kolejny. Wyobraźmy sobie teraz, że z czasem w naszym data center będziemy obsługiwać nowe workloady o pełnej specyfice. Może się okazać, że aby to zrobić w wydajny sposób, będzie potrzebne pewne przedefiniowanie naszej dotychczasowej sieciowej inżynierii ruchowej. Jeśli mamy urządzenia programowalne, to jesteśmy w stanie łatwo to zrobić, po raz kolejny stworzyć za pomocą P4 taki optymalny design data plane’u, naszej sieci data centerowej. To jest jeden przykład potencjalnych zastosowań.

Drugi przykład zastosowania związany jest z koncepcją NFV, czyli wirtualizacją funkcji sieciowych. To jest obecnie jeden z bardzo ważnych trendów w sieciach. Gdyby ktoś słyszał o tym po raz pierwszy, to nadmienię tylko, że w NFV chodzi o przeniesienie funkcji sieciowych z dedykowanego hardware’u na uniwersalne serwery, jakie stosuje się w IT. Wtedy te funkcje nazywamy tak zwanymi VNF-ami, czyli wirtualnymi funkcjami sieciowymi. I ten paradygmat V ma bardzo dużo zalet i to nie ulega kwestii.

Natomiast w dalszym ciągu jest cały szereg aspektów związanych z pewną efektywnością deploymentów opartych o tę koncepcję. Mam na myśli aspekty wydajnościowe przede wszystkim. Aby uzyskać zadowalający performance niektórych funkcji w pewnych konkretnych use case’ach, jedną z metod, jaką się stosuje jest tak zwany offloading, czyli przeniesienie niektórych jednostkowych funkcji z powrotem do hardware’u. Może to być przeniesienie całościowe lub częściowe. To drugie, można powiedzieć takie hybrydowe podejście, polega na wyodrębnieniu z oryginalnej funkcji dwóch oddzielnych części. Jedna część dalej jest realizowana jako funkcja wirtualna, natomiast ta druga, ta bardziej krytyczna ze względu na performance, jest wtedy wykonywana bezpośrednio na dedykowanym sieciowym hardwarze.

Nie trudno zgadnąć, że niezależnie od przypadku, aby móc to robić skutecznie i elastycznie, to potrzeba hardware’u programowalnego, takiego jak jakiś switch, który akurat mamy czy SmartNIC i wtedy możemy zrealizować na nich żądaną funkcjonalność tworząc po prostu odpowiedni kod w P4. Łatwo będzie także taki hardware potem przeprogramować, gdyby się okazało, że z czasem zmieniła nam się architektura albo charakter naszego deploymentu i trzeba będzie za chwilę offloadować jakąś inną funkcję.

Kolejny przykład obszaru, w którym P4 jest niezwykle użytecznym narzędziem, to jest tak zwana koncepcja INT. Ten skrót się rozwija jako inboud network telemetry i tutaj chodzi o stworzenie takiego wewnętrznego systemu telemetrycznego działającego w jakimś konkretnym segmencie sieci, który będzie gromadził cały szereg metadanych o pakietach na etapie przetwarzania ich w poszczególnych węzłach sieci, na całej ścieżce routingowej. To są na przykład takie informacje, jak opóźnienie, którego doznaje pakiet w danym węźle, zajętość kolejki, do której trafia w urządzeniu, obciążenie na łączu, z którego opuszcza urządzenie i tego typu informacje czy parametry.

Taki system może być bardzo użytecznym narzędziem, które pozwala na uzyskanie dużego wglądu w to, co się aktualnie dzieje w sieci. Ale nie będziemy teraz o tym mówić. Ten system można zrealizować na kilka sposobów. Jednym z nich jest enkapsulowanie tych wymienionych rodzajów metadanych w specjalne nagłówki, a następnie doklejenie ich w każdym pakiecie do jego nagłówków protokołowych i potem przesyłanie pakietu do kolejnego węzła, który zrobi to samo. Żeby to było możliwe, trzeba odpowiednio zaprogramować urządzenia, bo standardowe urządzenia sieciowe tak nie działają, żeby uzyskać takie zachowania, o jakie nam chodzi. Nie będzie wielkim zaskoczeniem pewnie, jak powiem, że świetnie nadaje się do tego właśnie P4.

👉 Czytaj dalej na: https://porozmawiajmyoit.pl/poit-119-jezyk-p4-i-programowanie-urzadzen-sieciowych/

kkempin’s dev blog

Dev and life blog. Thoughts about programming, design patterns, Ruby and life.

Krzysztof Kempiński

Written by

IT expert. Ruby on Rails/iOS/Elixir programmer. Blogger. Podcaster.

kkempin’s dev blog

Dev and life blog. Thoughts about programming, design patterns, Ruby and life.