Vyhledávání v IPv6 směrovači implementovaném v hradlovém poli David Antoš Jan Kořenek Vojtěch Řehák 2 Fakulta informatiky Masarykova univerzita v Brně Botanická 68a 602 00 Brno {antos rehak}@liberouter.org Fakulta informačních technologií Vysoké učení technické Božetěchova 22 612 66 Brno korenek@liberouter.org 1 Úvod Počítač v roli směrovače plní dva základní úkoly. Udržuje směrovací informace (tj. směrovací tabulku, nastavení paketového filtru, konfigurace atd.) a přepíná pakety. Přepínání paketů je činnost, při které operační systém prozkoumá hlavičky paketu, najde relevantní informace v tabulkách a na jejich základě rozhodne, kam (a jestli vůbec) paket vyšle. Protože hlavní brzdou tohoto postupu je propustnost PCI sběrnice, přirozeným řešením je postavit hardwarový akcelerátor, který bude provádět přepínání paketů. Akcelerátor Combo6, který vyvíjíme v rámci projektu Liberouter, bude sloužit přesně tomuto účelu. Vlastní přepínání paketů je operací na výkon nejkritičtější, na druhou stranu údržba tabulek je doménou řídícího počítače, který také může snadno zajišťovat komunikaci s uživatelem. Klíčovou částí přepínání paketů v Combo6 je vyhledání, jak se má s paketem naložit. Vstupem jsou údaje z hlaviček a výstupem popis, kam paket vyslat a jak se před vysláním má editovat. Úkolem softwarové podpory akcelerátoru je zajistit, aby přepínání paketů probíhalo zcela shodně s tím, jak by s pakety naložil operační systém. Z jeho pohledu se navíc karta bude chovat jako běžné síťové adaptéry. Jedinou změnou je, že pakety, které sama umí zpracovat, také (výrazně rychleji) zpracuje. V tomto článku popisujeme hardwarovou realizaci vyhledávacího stroje a jeho instrukční sadu. Zmiňujeme se také o původním návrhu, který sice nebyl použit, ale při jeho tvorbě jsme využili metod formální verifikace. Další část se věnuje architektuře softwarové podpory akcelerátoru, konceptu routovací/firewallovací tabulky a výpočtům vyhledávacích struktur, na kterých právě pracujeme. 1 Tento výzkum je podporován projektem 5. rámcového programu 6NET (IST-2001-32603) a projektem CESNETu Implementace IPv6 v síti CESNET2 (02/2003). 2 Práce vznikla za podpory grantu GAČR 201/03/0509.
2 Hardware Vyhledávací operace (stejně jako většina procesů v routeru) jsou prováděny pomocí programovatelného hardwaru, Field Programmable Gate Arrays (FPGA). Pro uložení vyhledávacího programu používáme dva typy pamětí. Jednou z nich je obsahem adresovatelná paměť (Content Addressable Memory, CAM 3 ), konkrétně Micron MT75W16Y136HBB. Tento typ dovoluje konfiguraci pro 4K slov šířky 272 bitů (a řadí se tím mezi nejširší dostupné CAM). Dále dovoluje použití don t care bitů. Typická přístupová doba je 80 ns. Druhým typem paměti je statická RAM s typickou přístupovou dobou 10 ns. 2.1 Vstupy a výstupy Vstupem vyhledávacího stroje je struktura nazývaná Unifikovaná hlavička, fyzicky uložená jako sada registrů. Unifikovaná hlavička je pevná datová struktura obsahující důležité informace extrahované z hlaviček paketu. Struktura je 596 bitů dlouhá a mezi její hlavní pole patří L2 a L3 stavové registry, zdrojová a cílová MAC adresa, VLAN id, zdrojová a cílová IP adresa a port,... Každé ze čtyř vstupních rozhraní je obsluhováno jedním vyhledávacím strojem. Každý stroj používá čtyři sady registrů pro uložení Unifikovaných hlaviček. Tělo paketů je předchozími bloky uloženo do hlavní paměti, takže jedinou informací, kterou musí navíc vyhledávací stroj předávat, je identifikace paketu. Každý vyhledávací stroj čte Unifikované hlavičky a vyhledá ukazatel editačního programu. Editační program popisuje, jak a kterým rozhraním má být paket vyslán. Paket může být vyslán několika rozhraními, dokonce i jedním rozhraním několikrát. Jedním z výstupních rozhraní je také operační systém. Z jeho pohledu se akcelerátor chová jako běžné síťové rozhraní. Tímto způsobem můžeme 1. generovat ICMP odpovědi na chybné pakety, 2. doručovat pakety určené hostitelskému počítači, 3 CAM dostane na vstup slovo (délky typicky desítek až stovek bitů) a odpoví adresou, na které se slovo nachází.
~ 17 x 32 bit chunks of key Default 1 CAM Resolution 1 hypothesis (must check rest of the key) Resolution 1 Resolution block hypothesis (several possible resolutions) Default match all Default handling n ary tree based on part of the key Resolution 2 X hypothesis Default 3 Resolution 3 Default 2 Resolution 2 Posibly cascaded the structures for more compliet cases with variable "brand span" Resolution hypothesis checking includes port range checking if needed Obrázek 1 Běh vyhledávacího programu 3. sledovat síťový provoz, 4. zpracovat pakety, které akcelerátor sám neumí. Samozřejmě pakety procházející softwarem jsou zpracovány pomaleji. 2.2 Vyhledávací procesor Vyhledávací procesor prochází stromovou strukturou, program je spuštěn pro každou Unifikovanou hlavičku od začátku. Instrukční sadu navrhl Pavel Zemčík. Instrukce lze rozdělit na tři typy: CAM Step, List vyhledá podmnožinu registrů v CAM. Parametr List je bitová maska určující, které registry mají být vybrány. Výsledná hodnota vrácená CAM slouží jako ukazatel na pokračování vyhledávacího programu. (Z pohledu hardwarové realizace je diskutabilní, zda chápat CAM jako instrukci. Jedná se totiž pouze o přístup do asociativní paměti.) Porovnávací instrukce porovnávají registry Unifikované hlavičky s konstantami. Testovat lze celou škálu relací, rovnost, menší než atd. EXE Queue je terminální instrukcí. Uloží identifikaci paketu a parametr Queue do výstupní fronty. Parametr je ukazatelem na editační program.
CAM ifc. SRAM ifc. HFE ifc. FIFO Control Start addr. Process Unit HFE ifc. FIFO Control CAM Block Start addr. Process Unit MX Replicator interface HFE ifc. FIFO Control Start addr. Process Unit HFE ifc. FIFO Control Start addr. Process Unit Input Buffers Obrázek 2 Lookup Procesor Bloková struktura vyhledávacího stroje Instrukce prvních dvou typů jsou relativní podmíněné skoky. Délka skoků je určena parametrem Step. Instrukce jsou kódovány jako 36-bitová slova potřebujíce až 32bitové argumenty, využíváme pro uložení operačních znaků paritní bity statické paměti. Pokud se na vyhledávací program díváme jako na stromovou strukturu (přesněji řečeno trie), CAM reprezentuje první úrovně stromu a další instrukce zbytek. Důležitou vlastností je, že jednotlivé úrovně stromu mají rozdílné schopnosti. Například CAM umí don t care bity, ale nelze v ní efektivně provádět test na je menší než. Pro ostatní instrukce platí opačné tvrzení. 2.2.1 Hardwarová realizace Vyhledávací procesor sestává z CAM bloku, který realizuje vyhledávání v asociativní paměti, a z procesních jednotek, které provádějí instrukce uložené v SRAM. CAM blok je pouze jeden, ovládá asociativní paměť a provádí cyklicky vyhledávání pro jednotlivá rozhraní. Výsledkem je adresa programu pro procesní jednotku. Každé rozhraní má jednu procesní jednotku, jednotky sdílejí statickou paměť a přistupují do ní v časových slotech. CAM a procesní bloky běží na sobě nezávisle. V původním návrhu jsme předpokládali, že vyhledávání v CAM a přístup do SRAM provádí jeden blok. Bylo tedy nutno zajistit, aby první přístup do CAM byl synchronizován tak, aby se konec operace kryl časově s časovým slotem pro přístup do statické paměti.
Obrázek 3 Časové sloty pro sdílení CAM a SRAM Současné řešení je výrazně jednodušší, nicméně popíšeme původní variantu. Při jejím vývoji bylo použito metod formální verifikace a sekce 2.3 popisuje detaily. Nyní se věnujme již neplatnému návrhu. Každý vyhledávací stroj má časový slot pro přístup do SRAM. Instrukce CAM končí přístupem do SRAM, takže začátky instrukcí CAM musí být nastaveny tak, aby provádění CAM končilo v časovém slotu pro přístup daného stroje do statické paměti. Obrázek 3 ukazuje příklad běhu procesoru. Horizontální čáry rozdělují graf po 10 ns. LUP1 až LUP2 jsou vyhledávací procesory a obdélníky označují, jakou činnost provádějí. V sekci load data se registry kopírují do CAM. V tomto okamžiku CAM nemůže dělat nic jiného. Během latency time CAM provádí vyhledávání, během něhož může dostávat další data. Malý slot SR na konci zpracování vybírá jako výsledek další instrukci ze statické paměti. Fáze COMP je zpracování instrukce, které končí přístupem do statické paměti. V dolní části obrázku je přehled možných přístupů do SRAM označený čísly strojů, které zrovna vlastní časový slot. Konečně, CAM slot je čas, kdy vyhledávací stroj může přistoupit do CAM, pokud CAM není používána jiným strojem. Přesněji řečeno, pokud je na začátku časového slotu CAM volná, pak stroj vlastnící slot jej může využít pro fázi load data. Naprosto není zřejmé, že tento mechanismus zabrání zablokování a poskytuje spravedlivé plánování. Pokoušeli jsme se tyto vlastnosti dokázat konvenčními metodami (tj. ad-hoc), nicméně jsme tento postup zavrhli jako příliš náročný a neefektivní. V následující sekci
popíšeme použití metod formální verifikace. Pomocí těchto metod lze poměrně snadno ukázat, že žádná fronta nemůže stárnout. 2.3 Verifikace sdílení CAM a SRAM Rozhodnout, zda navržené přístupy do pamětí jsou korektní, je typickým úkolem pro formální verifikaci. Požadované vlastnosti byly prověřeny symbolickým model checkerem NuSMV. Model checking 4 je formální metoda dovolující automaticky dokázat, zda model systému na určité úrovni abstrakce splňuje zadanou specifikaci. Náš model sestává z pěti synchronních modulů, modulu timer a čtveřice vyhledávacích procesorů. Modul timer počítá 10ns časové sloty modulo 4 v proměnné time. Vyhledávací procesory lup0 až lup3 simulují čtyři vyhledávací stroje sdílející CAM a SRAM. Každý vyhledávací procesor se nachází v jednom ze šesti stavů, změnit stav může, jen pokud proměnná time je rovna jeho číslu. Význam a chování každého stavu popíšeme dále. Stav sleep simuluje chování procesoru s prázdným vstupním bufferem. Další stav závisí na tom, zda přijde paket a zda CAM není používána jiným strojem. Jestliže žádný paket nepřišel, procesor zůstává ve stavu sleep, jinak přechází do wait nebo load data podle toho, zda CAM je používána jiným strojem. Procesor je ve stavu wait, jestliže chce začít zpracovávat paket, ale CAM je obsazená. Délka pobytu ve stavu wait závisí na dostupnosti CAM. Jakmile se CAM uvolní, procesor přechází do stavu load data. Stav load data reprezentuje načítání dat do CAM a je kritickou sekcí pro sdílení této paměti. Dalším stavem je latency1. Stavy latency1 a latency2 reprezentují čekání na výsledek. Navíc latency2 zahrnuje poslední SRAM časový slot. Po latency2 následuje řada stavů comp. Stavy comp simulují výpočet v paměti SRAM. Jeden comp stav odpovídá provedení jedné instrukce, na jejímž konci se přistupuje do paměti SRAM. Počet instrukcí není omezen. Z předchozího popisu chování je zřejmé, že následujícím stavem může být comp, sleep, wait nebo load data. Abstrahujeme od plnění vstupního bufferu a od počtu instrukcí, které se vykonávají v paměti SRAM, tj. každé rozhodnutí založené na popsaných vlastnostech modelu je nahrazeno nedeterministickým výběrem. Na tuto část chování modelu tedy neklademe žádné omezující podmínky. Námi popsaný (a následně ověřený) model je tedy obecnější než předpokládaná realita, neboť umožňuje i stále prázdný vstupní buffer či nekonečné setrvání v comp stavech. Ověřené vlastnosti pak mají obecnější (silnější) vypovídací hodnotu. Právě vhodná volba abstrakce, která zachová pravdivost ověřované vlastnosti, je nejúčinějším způsoben, jak vlastní výpočet ověření zjednodušit, a tím zrychlit, či dokonce umožnit. Kód níže ukazuje skutečnou implementaci popsaného algoritmu sdílení CAM a SRAM. 4 Pro podrobné informace odkazujeme na [Barnat et al., 2002].
MODULE timer_type(time) ASSIGN next(time) := (time+1) mod 4; MODULE lup (me, time, CAM_busy) VAR state : {sleep, wait, load_data, latency1, latency2, comp}; ASSIGN init(state) := sleep; next(state) := case!(time=me) : state; state=sleep &! CAM_busy : {sleep, load_data}; state=sleep : {sleep, wait}; state=wait &! CAM_busy : load_data; state=wait : wait; state=load_data : latency1; state=latency1 : latency2; state=latency2 : comp; state=comp &! CAM_busy : {comp, sleep, load_data}; state=comp : {comp, sleep, wait}; esac; DEFINE SRAM_used := time=me & (state=latency2 state=comp); MODULE main VAR time : 0..3; lup0 : lup(0,time,cam_busy); lup1 : lup(1,time,cam_busy); lup2 : lup(2,time,cam_busy); lup3 : lup(3,time,cam_busy); timer: timer_type(time); ASSIGN init(time) := 0; DEFINE CAM_busy := lup0.state = load_data lup1.state = load_data lup2.state = load_data lup3.state = load_data; Prověřili jsme všechny zajímavé vlastnosti tohoto modelu jako výlučnost přístupu do SRAM, výlučnost přístupu do CAM a spravedlnost přístupu do CAM (tzn. neblokující a nestárnoucí přístup). Navíc jsme spočetli, že maximální délka čekání na CAM je 120 ns. Verifikované formule a výsledky verifikací jsou ukázány níže.
-- Mutual exclusion of accesses to SRAM -- specification AG (!(lup0.sram_used & lup1.sram_used lup0.sram_used & lup2.sram_used lup0.sram_used & lup3.sram_used lup1.sram_used & lup2.sram_used lup1.sram_used & lup3.sram_used lup2.sram_used & lup3.sram_used)) is true -- Mutual exclusion of accesses to CAM -- specification AG (!(lup0.state = load_data & lup1.state = load_data lup0.state = load_data & lup2.state = load_data lup0.state = load_data & lup3.state = load_data lup1.state = load_data & lup2.state = load_data lup1.state = load_data & lup3.state = load_data lup2.state = load_data & lup3.state = load_data)) is true -- Fairness of using CAM (no starving, no blocking) -- LTL specification G ((lup0.state = wait -> F lup0.state = load_data) & (lup1.state = wait -> F lup1.state = load_data) & (lup2.state = wait -> F lup2.state = load_data) & (lup3.state = wait -> F lup3.state = load_data)) is true -- The maximal length of waiting for the CAM access -- MAX(lup0.state = wait, lup0.state = load_data) is 12 -- MAX(lup1.state = wait, lup1.state = load_data) is 12 -- MAX(lup2.state = wait, lup2.state = load_data) is 12 -- MAX(lup3.state = wait, lup3.state = load_data) is 12 3 Software Připomeňme, že cílem celého návrhu je učinit Combo6 naprosto nezávislým na nástrojích používaných v operačním systému k nastavení a sledování síťového provozu. Proto v nejširší míře používáme standardních prostředků operačního systému a všechny výjimky musí být náležitě zváženy.
redirect,... tcpdump,... firewall rules configuration routing algorithm primary r/f table HW version of r/f generator PCI driver HW pre processed table SW CAM SRAM HW look up procesor unified headers (Sets of Registers) Obrázek 4 3.1 Rozhraní Bloková struktura vyhledávacího stroje a podpůrného softwaru Na nejnižší úrovni obslužný démon vytváří programy pro hardwarový vyhledávací stroj a přes driver je kopíruje do hardwarových pamětí. Driver aplikacím poskytuje Un*xové zařízení (/dev/combo) a aplikační rozhraní. Typickými operacemi na API jsou čtení a zápis slov v SRAM, řádků CAM (272 bitů širokých) a dále bloků těchto položek. Driver také zajišťuje ostatní operace s Combo6, například zavádění firmwaru, čtení stavových informací a statistik, přenos paketů a podobně. Než se začneme věnovat rozhraní démona směrem k operačnímu systému, shrňme stručně, jak jádro obsluhuje došlé pakety. Jádro udržuje směrovací tabulku. Ta je buď nastavena ručně nebo spravována směrovacím démonem. Filtrovací pravidla jsou popsána v nějakém jazyce, například ipchains nebo ipfw, a uložena v interních strukturách jádra. Při zpracování paketu jádro porovná hlavičky paketu s těmito tabulkami a rozhodne, jak s paketem naloží. Jednoduše řečeno, chceme tento mechanismus obejít a ponechat zpracování paketu na akcelerátoru. Musíme tedy od systému zjistit konfiguraci rozhraní a současné nastavení směrovacích a filtrovacích tabulek. To můžeme získat dvěma způsoby. Můžeme modifikovat směrovacího démona, aby je řekl také nám. Hlavní nevýhodou tohoto přístupu je, že bychom museli zasahovat do kódu třetích stran a udržovat jej. Navíc bychom omezili uživatele Combo6 na směrovací démony, které jsme se rozhodli podporovat. Jiným způsobem, pro který jsme se také rozhodli, je vytvořit nástroj, který sleduje změny tabulek jádra a informuje nás o nich. Samostatnou kapitolou je filtrace paketů. Filtrační nástroje poskytují nepřeberně vymožeností a mechanismů. Neexistuje společný standard v žádném operačním systému, o portabilitě nemluvě. Tento problém dosud nemáme vyřešen. Bude nutno mimo jiné porovnat
vyjadřovací schopnosti používaných nástrojů s možnostmi jazyka vyhledávacího procesoru, který jsme popsali. Jak už bylo řečeno, potřebujeme démona, který sleduje změny ve směrovacích tabulkách jádra a předává nám je. Software pro výpočet hardwarových tabulek je k němu připojen přes rozhraní zvané RT-callback interface. Démon samotný bude rozdělen na systémově závislou a nezávislou část, aby portabilita byla co možná nejsnazší. Dalším nesnadným problémem je diagnostika provozu. Nástroje jako tcpdump modifikují tabulky jádra a vkládají filtry hledající požadované informace. Změny tohoto rázu musí být také předány přes RT-callback interface. Předpokládáme, že v první fázi budou pakety podléhající nastavení filtru kompletně odeslány do softwaru. Aby nedošlo k fatálnímu snížení výkonu, je žádoucí i v takovém případě poskytovat softwaru nejmenší nadmnožinu požadovaných paketů, jak je to jen možné. 3.2 Routing/firewalling tabulka RT-callback rozhraní oznamuje změny směrovacích a filtrovacích pravidel. Protože v akcelerátoru máme jediný běh vyhledávacího stroje pro rozhodnutí, jak s paketem naložit, musíme zkombinovat všechny tyto zdroje do jediného vyhledání. Proto jsme vytvořili koncept routovací/firewallovací tabulky (r/f tabulky). R/f tabulka je v principu směrovací tabulka, na jejíž každý řádek předem aplikujeme filtrovací pravidla. Obecně se tak jedna položka routovací tabulky může rozpadnout do řady r/f položek. Tento koncept je nutno ještě důkladně analyzovat a porovnat jeho vyjadřovací schopnosti se schopnostmi obvykle používaných filtrovacích jazyků. Při změně směrovací tabulky, nastavení firewallu nebo konfigurace je třeba příslušné úpravy provést i v r/f tabulce. 3.3 Výpočet vyhledávacího programu Vyhledávací program je fyzicky umístěn v CAM a SRAM pamětech. Je vypočten z r/f tabulky. Je vhodné si uvědomit, že hardwarová podoba vyhledávacího programu nemusí dovolit rekonstrukci původní r/f tabulky, může například obsahovat expandované řetězce. Předpokládáme také, že vyhledávací program bude silně optimalizován. V prvních verzích plánujeme pouze aktualizování celých tabulek naráz. Generátor vezme r/f tabulku, vymyslí optimalizace a vypočítá vyhledávací program. Jednoduchým způsobem přepínání na novou tabulku je technika dvojitého bufferu: paměť CAM rozdělíme na poloviny, jedna se používá pro produkční práci, obsah druhé se upravuje. Pak se atomicky používání obou částí přepne. Uvědomme si, že současně je nutno měnit obsah SRAM. Pro budoucí verze chceme vytvořit techniky pro opravy pouze částí vyhledávacího programu. Přepisování dat přináší problémy s časováním a platností záznamů. Změny v tabulkách musejí probíhat atomicky. Celá operace musí být schopna modifikovat hardwarové tabulky v čase řádu nejvýše sekund.
Na celý problém převodu r/f tabulky na vlastní instrukce vyhledávacího programu lze pohlížet jako na minimalizaci speciálního konečného automatu za silných omezujících podmínek. 4 Závěr Jak si čtenář zajisté povšiml, úroveň abstrakce se během článku zvyšuje. To také odpovídá stavu projektu. V současnosti máme k dispozici softwarový simulátor vyhledávacího procesoru. Hardware je dokončen a hlavní úsilí směřujeme do vývoje generátoru r/f tabulek a výpočtu vyhledávacího programu. Popsali jsme architekturu jedné z klíčových částí akcelerátoru Combo6. Věnovali jsme se hardwarovému i softwarovému návrhu. Vývoj směřuje k funkčnímu prototypu směrovače, nicméně některé zajímavé milníky už byly dosaženy našli jsme společnou řeč se skupinou formálních verifikací, o čemž někteří naši skeptičtější kolegové dlouho pochybovali. Dosáhli jsme tak kýženého bodu, kdy se teorie a praxe setkávají. 5 Reference Antoš, D. (2002). Overview of Data Structures in IP Lookups. Technical Report 9/2002, CESNET. Antoš, D. (2003). Associative Memories for IP Packet Routing, PhD Thesis Proposal. http://www.fi.muni.cz/~xantos/pgs. Masaryk University Brno. Barnat, J., Brázdil, T., Krčál, P., Řehák, V. and Šafránek, D. (2002). Model Checking in IPv6 Hardware Router Design. Technical Report 8/2002, CESNET. Cheung, G. and McCanne, S. (1999). Optimal Routing Table Design for IP Address Lookups Under Memory Constraints. In INFOCOM (3), pages 1437 1444. Liberouter, (2003). Liberouter Project WWW Page. http://www.liberouter.org. McAuley, A. J. and Francis, P. (1993). Fast Routing Table Lookup Using CAMs. In INFOCOM (3), pages 1382 1391. Nilsson, S. and Karlsson, G. (1999). IP-Address Lookup Using LC-Tries. In IEEE Journal on Selected Areas in Communications, pages 1083 1092. Novotný, J. (2002). Projekt routeru IPv6. Zpravodaj ÚVT MU, 1/2002:10 12. In Czech. Novotný, J., Fučík, O. and Kokotek, R. (2002). Schematics and PCB of COMBO6 card. Technical Report 14/2002, CESNET. Pao, D., Liu, C., Wu, A., Yeung, L. and Chan, K. S. (2002). Efficient Hardware Architecture for Fast IP Address Lookup. In IEEE INFOCOM 2002, pages 555 561. Sahni, S. and Kim, K. S. (2001). Efficient Construction of Multibit Tries for IP Lookup. IEEE/ACM Transactions on Networking. Waldvogel, M., Varghese, G., Turner, J. and Plattner, B. (2001). Scalable High-Speed Prefix Matching. ACM Transactions on Computer Systems, 19(4):440 482.