Jazyk P4 jako budoucnost SDN

I my na CESNETu jsme se pochopitelně setkali s fenoménem Software Defined Networking – SDN. Ten se stal populárním, protože slibuje možnost efektivně a rychle měnit konfiguraci a využití síťové infrastruktury – tedy něco, co by se v naší síti mohlo velmi dobře uplatnit! Aktuální implementace SDN, nazvaná OpenFlow, si našla cestu do mnoha reálných sítí, má však i určité nevýhody, které jsou spojeny s rozšiřitelností dalšího zpracování paketů a počtem podporovaných protokolů. Technologie zkrátka ještě není dostatečně zralá, proto jsme s jejím nasazením zbytečně nespěchali. Existující neduhy OpenFlow se snaží vyřešit svým přístupem jazyk P4. Ten slibuje skutečné a důkladné oproštění od starých protokolů a modelů fungování sítí. S jazykem P4 si svou síťovou infrastrukturu konečně naprogramujeme, nikoliv pouze nakonfigurujeme. Proto jsme se “pé čtyřkou” začali zabývat, i když zatím spíš na výzkumné úrovni.

Software-Defined Networking a OpenFlow

S rozvojem, rostoucí rychlostí a složitostí počítačových sítí se stále více objevuje potřeba efektivnější správy síťové infrastruktury. Navíc se stále častěji používají aplikace, které potřebují zasahovat do síťové infrastruktury a efektivně měnit její konfiguraci, například z důvodů bezpečnosti, směrování síťových toků, load-balancingu, atd. Plnění takových úkolů je však velmi nelehké v infrastruktuře, kde je každý síťový prvek autonomním a samostatně konfigurovaným zařízením. Celkové chování sítě je totiž komplexní kombinací funkcí všech těchto zařízení. Adninistrátor takové sítě si klade pořád stejnou otázku: Která zařízení a jak mám překonfigurovat, abych změnil chování sítě požadovaným způsobem, a přitom neovlivnil stávající služby? Odpověd je podstatně jednoduší v podání SDN, které přinásí následující výhody:

  • Přímá konfigurovatelnost – díky oddělení řídicí a datové vrstvy
  • Abstrakce – pro většinu činností nemusíme znát přesnou topologii sítě
  • Centralizace – přináší výhody během správy sítě, řízení toku dat v síti, atd
  • Otevřený standard – přináší nezávislot na výrobci síťového hardware
  • API – S kontrolérem může uživatel nebo aplikace komunikovat přes standardizované API z aplikační vrstvy

01

Obrázek 1: Architektura SDN

OpenFlow je zdaleka nejrozšířenější protokol sloužící pro komunikaci mezi řídící a datovou vrstvou. Je tedy určitým prostředkem, díky kterému můžeme realizovat koncept SDN. Tento komunikační protokol umožňuje konfigurovat síťové prvky – přepínače. Děje se tak především prostřednictvím plnění tabulek, které přiřazují síťovým tokům správné akce. Nad každým tokem tak můžeme spouštět různé akce, které mohou jejich pakety modifikovat, blokovat, posílat kontroléru, atd. Obvyklý scénář je, že jakmile přepínači přijde paket, se kterým si “neví rady” (protože nenašel odpovídající záznam v tabulce), odešle jej kontroléru. Kontrolér provede rozhodnutí a odpoví přepínači tím, že mu do jeho tabulky vloží správné pravidlo. Přepínač se tak postupně “učí” jak zpracovávat pakety jednotlivých toků.

Tok může být charakterizován různými políčky protokolů, které jsou přenášené v paketech. Nejčastěji je tok charakterizován pomocí pětice (sIP, dIP, sPort, dPort, Proto), kde sIP/dIP je zdrojová/cílová adresa, sPort/dPort je zdrojový/cílový port a Proto definuje transportní protokol (TCP nebo UDP). OpenFlow však umožňuje provádět klasifikaci toku i na základě vstupního portu, zdrojových/cílových MAC adres, EthType (políčko, které slouží pro specifikaci přenášeného protokolu v datové části Ethernetového rámce), hodnoty VLAN tagů, příznaků TCP protokolu, atd. Každá verze OpenFlow (aktuálně verze 1.5) typicky přináší nové podporované protokoly, které se mohou použít v průběhu identifikace toku. Ukázka počtu podporovaných protokolů je v tabulce.

Verze OpenFlow Datum Podporované protokoly
1.0 Prosinec 2009 12 políček protokolů (Ethernet, IPv4, …)
1.1 Únor 2011 15 políček protokolů (přidáno MPLS, metadata mezi tabulkama)
1.2 Prosinec 2011 36 políček protokolů (ARM, ICMP, IPv6,…)
1.3 Červen 2012 40 políček protokolů
1.4 Říjen 2013 41 políček protokolů
1.5 Prosinec 2014 45 políček protokolů

Počet podporovaných protokolů v OpenFlow.

Hlavním omezením OpenFlow je uzavřenost na podporované protokoly a akce v dané verzi. Nemůžeme tak jednoduše využít k identifkaci nový protokol, protože ho OpenFlow přepínače a kontrolér prostě neznají. Musí se napřed provést upgrade. V případě softwarové implementace přepínače není situace zcela neřešitelná. Pokud máme k dispozici zdojové kódy přepínače a kontroléru, můžeme si vytvořit vlastní variantu OpenFlow, rozšířenou o podporu našeho protokolu. Ukázka softwarových implementací OpenFlow přepínače, ktery je je dostupný pod open source licencí. Softwarově implementované přepínače mají však omezený výkon a nejsou tak vhodné pro vyspělou vysokorychlostní infrastrukturu sítě CESNET. V takovém prostředí se využívají hardwarové OpenFlow přepínače, ve kterých však upgrade na novou verzi OpenFlow vetšinou znamená výměnu celého zařízení. Jsme tedy tak trochu tam, kde jsme byli před OpenFlow. Tuto nevýhodu se snaží řešit jazyk P4.

Jazyk P4

P4 (Programming Protocol-independent Packet Processors) [4] je vysokoúrovňový jazyk pro programování protokolově nezávislých síťových procesorů, který je nedávným příspěvkem do SDN ekosystému. Jeho hlavním úkolem je možnost volně definovat zpracování paketů v síťových zařízeních. Klade důraz nejen na programovatelnost, ale také protokolovou a platformní nezávislost. P4 rozlišuje dva režimy práce zařízení: konfiguraci a normální provoz (viz. obrázek 2). Během konfigurace se do zařízení nahrává program v jazyce P4 a interně se kompiluje do reprezentace, která je pro dané zařízení nejvhodnější. To znamená, že program v jazyce P4 je možné přeložit pro běh na prakticky libovolném síťovém zařízení (které podporuje P4), bez ohledu na jeho vnitřní architekturu (např. CPU, GPU, síťový procesor, hradlové pole FPGA, …).

Po naprogramování zařízení se přejde do normálního provozu, ve kterém je režim práce podobný OpenFlow – je zde opět centrální kontrolér, který řídí všechna zařízení prostřednictvím plnění tabulek.

02

Obrázek 2 : Režimy P4 zařízení

Vlastní síťové zařízení můžeme v P4 popsat pomocí definice pěti základních operací síťového zařízení:

  1. Specifikace formátu hlaviček protokolů, které bude síťové zařízení podporovat.
  2. Specifikace procesu parsování. V jazyce P4 se pro specifikaci parsování používá konečný automat, kterým je možném vyjádřit další postup zpracování v závislosti na hodnotách políček v aktuálně zpracovávaném protokolu.
  3. Specifikace tabulek, které mapují toky na akce. Mají podobnou funkcionalitu jako flow tabulky v OpenFlow, ale mají větší volnost ohledně specifikace spouštených akcí. Navíc přináší i více různých režimů pro proces porovnávání extrahovaných dat s hodnotami v tabulce. Máme tedy dostupné režimy jako LPM (Longest Prefix Match), maskování (stejné jako v případě OpenFlow), definovaný rozsah hodnot a jiné. Každý záznam v tabulce spouští právě jednu akci.
  4. Specifikace akcí, které se budou provádět nad daným tokem. Samotný jazyk P4 obsahuje určitou množinu takzvaných primitivních akcí, které se poté mapují na dostupné zdroje dané cílové platformy. Jazyk umožňuje volat i uživatelsky definované akce, které se většinou skládají z primitivních a dalších uživatelských akcí.
  5. Specifikace kontrolního programu dává vše předchozí dohromady. Především umožňuje definování kriterií, která se použijí pro výběr následující tabulky. Jsou dostupné i různé režimy jako je výběr podle spuštěné akce, výběr na základě nalezení/nenalezení záznamu v tabulce, atd.

Těchto základních pět operací můžeme identifikovat v každém síťovém zařízení. Následující text se bude detailněji věnovat jednotlivým částem tohoto jazyka.

Specifikace formátu hlaviček

Deklarace hlavičky je velmi podobná deklaraci struktury v jazyce C. V jazyce P4 se jednotlivé části hlavičky zapisují ve formátu název : šířka v bitech;. Jako příklad můžeme uvést deklaraci ethernetové hlavičky:

header_type ethernet_t {

fields {

dstAddr : 48;

srcAddr : 48;

etherType : 16;

}

}

Předchozí příklad ukazuje definici hlavičky, kde jsou předem známé velikosti jednotlivých políček a celkovou délku je tedy možné vypočítat jako sumu všech jejích členů. Tento přístup však není možný u protokolů, které přímo v hlavičce obsahují celkovou délku – například rozšiřující hlavičky IPv6 protokolu. Jazyk P4 myslí i na tyto případy a programátor tak může definovat vzorec, který se použije pro výpočet délky pomocí klíčového slova length. Jako příklad můžeme uvést deklaraci rozšiřující hlavičky IPv6:

header_type ipv6_ext_t {

fields {

nextHdr     : 8;

totalLen   : 8;

frag       : 12;

padding     : 3;

fragLast   : 1;

}

length : (totalLen + 1) * 8;

max_length : 1024; // Bytes

}

Specifikace parsování

Proces parsování je v jazyce P4 popsán pomocí konečného automatu. Ten se typicky skládá z definice stavů a přechodů do následujících stavů. Vše důležité vysvětlíme na následující ukázce:

header ethernet eth;

parser ethernet {

extract(eth);

switch(eth.ethertype) {

case 0xAB00: ingress_control;

case 0x8100: vlan;

case 0x9100: vlan;

case 0x800: ipv4;

case 0xA100 mask 0xF100 : myProto;

}

}

Klíčové slovo header slouží pro deklaraci proměnné eth. Dále se definuje stav parseru s názvem ethernet, kde se provádí samotná extrakce dat do proměnné eth (klíčové slovo extract) a přechod do nového stavu. Pro samotný přechod se používají vyparsovaná data, která jsou použita jako parametr do switch konstrukce. Ten může v parametru obsahovat více políček, které jsou odděleny operátorem “,” a tvoří tak jeden binární vektor. Ten je následně použit pro porovnání s hodnotou v case.

Mohou však nastat i situace, kdy nechceme použít exaktní hodnotu z aktuálně zpracovávaného paketu. Jazyk P4 tento problém řeší pomocí klíčového slova mask. V tomto případě se použije aktulního hodnota, provede se logický součin s maskou a výsledek se porová s hodnotou vlevo. V našem případě se použije maska s hodnotou 0xF100 a výsledek se porovnává s hodnotou 0xA100.

Následujícím stavem nemusí být pouze parser (v našem případě vlan,ipv4 nebo myProto), ale také kontrolní program (v našem případě ingress_control). V takovém případě je parsování ukončeno a spuštěno následující zpracování v tabulkách.

Vstupním bodem celého P4 programu je vždy parser s názvem start, který může vypadat následovně:

parser start {

return parse_eth;

}

Specifikace tabulek

Tabulka slouží k mapování vyparsovaných políček na danou akci (anglicky match+action). Při specifikaci tabulky se uvádí:

  1. Políčka hlaviček protokolů, která se použíjí pro identifikaci nejvhodnějšího záznamu v tabulce + jejich algoritmy na porovnávání hodnot. Zápis je ve formátu políčko : algoritmus;
  2. Seznam podporovaných akcí, které se mohou po nalezení záznamu v tabulce spustit.

Ukázka zápisu tabulky v jazyce P4:

table filter {

reads {

ipv4.srcAddr : lpm;

tcp.dstPort : exact;

}

actions {

PushVlan;

_permit;

NoOp;

}

}

Jednotlivá políčka, na která bude tabulka reagovat, se udávají do části reads. Samotný seznam možných akcí je pak uveden v části actions. V případě nalezení záznamu v tabulce se spustí právě jedna akce.

Tabulky jsou po zapnutí zařízení prázdné a záznamy musí být založeny při běhu. Záznam si můžeme představit jako hodnoty políček (struktura odpovídá reads), příslušnou akci (jedna ze sekce actions) a její parametry.

Specifikace akcí

Jazyk P4 definuje množinu primitivních akcí, které mohou být použity pro konstrukci složitějších uživatelsky definovaných akcí. Následující ukázka byla převzata z Computer Communication Review 2014:

action add_mTag(up1, up2, down1, down2, egr_spec) {

add_header(mTag);

// Copy VLAN ethertype to mTag

copy_field(mTag.ethertype, vlan.ethertype);

// Set VLAN’s ethertype to signal mTag

set_field(vlan.ethertype, 0xaaaa);

set_field(mTag.up1, up1);

set_field(mTag.up2, up2);

set_field(mTag.down1, down1);

set_field(mTag.down2, down2);

// Set the destination egress port as well

set_field(metadata.egress_spec, egr_spec);

}

Akci si můžeme představit jako funkce v jazyce C (jejich zápis je poměrně podobný). Stejným rysem je i možnost předání parametrů. V jazyce P4 jsou parametry vyčteny a předány akci z tabulky, která byla popsána v předchozí části textu (tyto parametry jsou vloženy v průběhu zakládání záznamu).

V naší ukázce se za VLAN hlavičku vloží mTag (uživatelsky definovaná hlavička), zkopíruje se hodnota políčka ethertype (z VLAN tagu) do stejného políčka v mTag (aby bylo jasné, co bude následovat). Poté se políčko ethertype u VLAN tagu nastaví na hodnotu 0xaaaa, aby se signalizovala přítomnost mTag hlavičky. Další řádky kódu poté nastavují další políčka protokolu mTag a definují výstupni port (políčko metadata.egress_spec). Akce add_header, copy_field a set_field patří mezi primitivní akce. Jazyk P4 však obsahuje vetší počet takových základních funkcí. Jejich kompletní seznam je možné nalézt v kompletní specifikaci jazyka.

Specifikace kontrolního programu

V této fázi máme definován proces parsování, uživatelské akce a tabulky. Posledním krokem je tak specifikace využívání jednotlivých tabulek. Tohoto můžeme docílit v jazyce P4 specifikací control bloku. Následující ukázka byla převzata z Computer Communication Review 2014:

control main() {

// Verify mTag state and port are consistent

apply(source_check);

// If no error from source_check, continue

if (!defined(metadata.ingress_error)) {

// Attempt to switch to end hosts

apply(local_switching);

if (!defined(metadata.egress_spec)) {

// Not a known local host; try mtagging

apply(mTag_table);

}

// Check for unknown egress state or

// bad retagging with mTag.

apply(egress_check);

}

}

Spouštění jednotlivých tabulek je v případě jazyka P4 realizována pomocí klíčového slova apply. Uvedený příklad slouží pouze jako ukázka definice této části programu. Apply zde slouží k “spuštění” tabulky. Zdrojový kód je dobře komentován.

Komunita vývojářů kolem jazyka P4 již vytvořila základní nástroje, které mohou být použity v jiných projektech. Všechny tyto nástroje jsou veřejně dostupné ve formě zdrojových kódů. Jeden z hlavních projektů je P4-HLIR. Jedná se o část P4 překladače, která vytvoří model pomocí objektů v jazyce Python. Výsledná objektová reprezentace je dostatečně dokumentována, aby programátor mohl vytvořit zbytek překladače. Můžeme tak vytvořit překladač z P4 do libovolné cílové technologie a využít k tomu již hotového lexikálního a syntaktického analyzátoru.

Ukázkou projektů, které využívají P4-HLIR, může být P4C-GRAPHS a P4C-BEHAVIORAL. Jedná se o ukázky překladače do kódu programu DOT (grafické znázornění P4 programu) a C++. Více zdrojových kódů, nástrojů a detailů je možné nalézt na stránkách projektu P4.

Využitím jazyka P4 se zabýváme i my na CESNETu, konkrétně v oddělení nástrojů pro monitoring a konfiguraci. Naše výzkumná skupina (www.liberouter.org) má dlouholeté zkušenosti se stavbou hardwarově akcelerovaných zařízení pro zpracování vysokorychlostního síťového provozu s využitím programovatelných hradlových polí FPGA. Využití vysokoúrovňového jazyka P4 pro popis chování zařízení se tedy přímo nabízí jako další logický krok.

Využili jsme projektu P4-HLIR a vytvořili překladač, který generuje VHDL kód hardwarového parseru pro hradlové pole FPGA. Struktura parseru je inspirovaná naším starším ručně psaným parserem (který jsme si nechali i patentovat), ale zdlouhavá ruční práce je tentokrát nahrazena skriptem v jazyce Python. Během pár sekund lze vygenerovat parser, který je schopen zpracovávat pakety na rychlosti nejnovějšího Ethernetového standardu 100 Gb/s. Náš přístup byl prezentován na konferenci Supercomputing 2015 v USA, s prací na P4 ale rozhodně nekončíme. Pracujeme na “deparseru”, tedy modulu s přesně opačným fungováním, který se uplatní při odesílání zpracovaného a modifikovaného paketu zpět do sítě. Dalším krokem bude automatická konstrukce tabulek podle P4 specifikace. V tu chvíli získáme kompletní P4 přepínač – vysokorychlostní síťové zařízení, které si konečně naprogramujeme aby fungovalo přesně tak, jak potřebujeme.

Pokud vás jazyk P4 zaujal, tak neváhejte a navštivte oficiální stránku P4, kde najdete projekt P4FACTORY. Ten obsahuje vše důležité, co budete pro implementaci svého P4 zařízení potřebovat. V tomto balíku jsou dostupné i zdrojové kódy, které můžete využít jako inspiraci ke svému vlastnímu projektu.

Pavel Benáček a Viktor Puš