martedì 5 aprile 2016

OpenFlow: nuova moda o nuovo Nirvana ?

Oggi mi trovo con piacere ad essere ospite di questa isola felice di condivisione, messa in piedi e portata avanti dal mio esimio collega Tiziano Tofoni (alias, l’Ammiraglio Tofonoto), per ampliare un po’ il discorso sul protocollo OpenFlowiniziato con questo post sul ruolo del BGP e MPLS nell'era SDN.

UN PO’ DI STORIA
Come ogni cosa, è bene partire dall’inizio (o come dicono gli inglesi “first things first”). L’idea del protocollo OpenFlow nasce dalle fucine dell’università di Stanford nel non troppo lontano 2008, portandosi all’attenzione del grande pubblico con un whitepaper carico di sogni e speranze dal titolo: “OpenFlow: Enabling Innovation in Campus Networks” (openflow-wp-latest.pdf). 

Obiettivo di questo articolo era di proporre ai produttori di apparati di rete, un modo per influenzare i meccanismi di forwarding di uno switch Ethernet, tramite la manipolazione di regole personalizzate di instradamento. Questo procedimento avrebbe aiutato i ricercatori nello studio e nel testing di nuovi protocolli, in una rete reale e di produzione. Il tutto senza la necessità di aprire le implementazioni proprietarie del piano di controllo degli apparati in commercio, ma semplicemente implementando un nuovo protocollo: OpenFlow appunto.

L’idea era di poter accedere alle tabelle di gestione dei flussi (flow table) già presenti nella maggior parte dei prodotti commerciali di diversi vendor, tramite un’interfaccia standard e open source. Così facendo, si sarebbe potuto avere un controllo sul traffico tale da poter maneggiare separatamente dei flussi sperimentali, lasciando inalterato il traffico di produzione. Già da questo primo articolo troviamo la presenza di un controllore esterno alla macchina ed una prima architettura di uno switch OpenFlow, come mostrato nella figura seguente.


(Figura tratta da OpenFlow® Switch Specification 1.0.0)

Venne quindi costituito l’OpenFlow Consortium (poi confluito nel Open Networking Foundation, ONF) a cui venne demandato il compito di mantenere e supportare lo sviluppo di OpenFlow. A distanza di un anno da questo primo articolo, nel dicembre del 2009, venne infine rilasciata la prima versione stabile, di OpenFlowla 1.0 (openflow-spec-v1.0.0.pdf).


OPENFLOW SWITCH
L’attuale “standard” dello switch OpenFlow è la versione 1.5.1, uscita giusto un anno fa, nel marzo del 2015 (openflow-switch-v1.5.1.pdf). Prenderò a riferimento questa versione nelle successive descrizioni del protocollo.

Tirando le somme, cerchiamo di dare una definizione di OpenFlow. L’ONF lo definisce (cito traducendo) come:

…la prima interfaccia di comunicazione standard tra il piano di controllo e il piano dati di una architettura SDN. Permette l’accesso diretto e la manipolazione del piano dati di un dispositivo di rete…

Questo sposta nettamente il focus lontano dal testing di nuovi protocolli, e ci fa approdare direttamente nel campo per noi di maggiore interesse: il Software Defined Networking (SDN) ! Iniziamo quindi a distinguere nel protocollo OpenFlow due attori: 
  • Il controller OpenFlow
  • Lo switch OpenFlow.
Il primo, che tratterò marginalmente, è un software capace di interagire con gli switch OpenFlow, usando appunto il protocollo OpenFlow. Spesso controlla più apparati contemporaneamente. Questa interazione avviene attraverso una interfaccia "lato sud" (southbound), logicamente identificata come OpenFlow Channel.

Il secondo è uno switch logico, costituito delle risorse gestite da OpenFlow. Si distingue ad alto livello in due tipologie: OpenFlow-only e OpenFlow-hybrid. La differenza sta nel fatto che le risorse del primo vengono gestite dal protocollo OpenFlow (completamente!), mentre l’altro ha risorse compatibili con il protocollo OpenFlow, ma è capace di lavorare autonomamente come uno switch comune. Quest’ultimo si avvicina maggiormente all’idea iniziale di quello che si ipotizzava essere uno switch OpenFlow nel whitepaper originale del 2008.

Analizziamo più nel dettaglio la struttura di queste risorse.

(Figura tratta da OpenFlow® Switch Specification 1.5.1)

CONTROL CHANNEL
Iniziamo da qualcosa che conosciamo: il Control Channel. Abbiamo già visto che l’OpenFlow Channel è il canale attraverso cui il controller e lo switch OpenFlow riescono a comunicare. Il Control Channel è semplicemente l’insieme degli OpenFlow Channel (può essere uno, o più di uno, o ... anche nessuno!), e dei rispettivi controller connessi ad essi. Questa comunicazione tra il controller e lo switch avviene secondo tre diverse metodologie:
  • Controller-to-switch
La comunicazione parte dal controller e può richiedere o meno una risposta. Di questa categoria fanno parte quei messaggi che sondano le funzionalità (FEATURES), le configurazioni (CONFIGURATION) o lo stato (READ-STATE) dello switch. Ma soprattutto fa parte il messaggio di inoltro di un pacchetto, dal controller verso lo switch (PACKET-OUT), per permetterne l’instradamento.
  • Asynchronous
La comunicazione parte dallo switch, senza sollecitazioni da parte del controller. Di questa categoria fanno parte quei messaggi che mantengono aggiornato il controller sullo stato delle porte (PORT-STATUS) o lo stato dei flussi (FLOW-MONITOR o FLOW-REMOVED). Anche l’invio di un pacchetto al controller, fa parte di questa categoria (PACKET-IN).
  • Symmetric
Questo genere di comunicazioni sono inoltrate da entrambe le parti senza sollecitazione. Di questa categoria fanno parte i messaggi di controllo come i ping (ECHO), i keepalive (HELLO) e i messaggi di errore (ERROR).

PORTE STANDARD
Un’altra forma di comunicazione che avviene tra lo switch OpenFlow e il mondo esterno è rappresentata dal traffico circolante tra le OpenFlow Port. Queste sono anche dette Standard Port e sono l’insieme di tutte le interfacce gestite dallo switch OpenFlow in ingresso o in uscita. Vengono distinte in tre tipologie: porte fisiche, porte logiche e porte riservate.

Le porte fisiche sono interfacce dello switch, con una corrispondenza uno-a-uno con una interfaccia hardware della macchina. Questo permette, ad esempio, di mettere in comunicazione diretta lo switch logico con un’interfaccia verso il mondo esterno. È anche possibile virtualizzare un’interfaccia fisica, riuscendo così a dedicare una porzione della stessa interfaccia a più porte fisiche dello switch OpenFlow.

Le porte logiche sono interfacce, utilizzate dallo switch, completamente astratte. Non hanno alcuna corrispondenza con una parte dell’hardware. Una porta logica può implementare una funzionalità di rete come un’interfaccia di loopback, un tunnel, così come può essere un multiplexer per diverse porte fisiche. La funzionalità principale è che il loro attraversamento sia totalmente trasparente al funzionamento dello switch, che deve semplicemente utilizzarle per instradarvi il traffico.

Infine, le porte riservate sono porte che nascondono una specifica funzionalità di forwarding. Nella specifica vengono definite alcune porte come Required, cioè da implementare obbligatoriamente, e alcune come Optional, appunto di carattere opzionale. La scelta di implementare o meno queste porte, dipende dal tipo di switch che vogliamo implementare. Nello specifico, implementando o meno le porte Optional, andiamo a creare uno switch OpenFlow del tipo OpenFlow-hybrid. Ci sono circa 9 tipologie di instradamento previste da queste porte logiche. tra le quali possiamo annoverare nelle obbligatorie:
  • ALL: rappresenta la via verso tutte le interfacce disponibili. Utilizzabile solo in uscita.
  • CONTROLLER: rappresenta il canale di comunicazione con il controller in ingresso e in uscita.
e tra le opzionali:
  • NORMAL: rappresenta il canale verso le tabelle di inoltro legacy. In parole povere è la strada da percorrere se si vuole fare gestire questo traffico come su un normale switch.
Le operazioni effettuate sulle varie porte, da specifica, devono essere sempre mantenute sotto controllo. Ogni aggiunta, modifica o rimozione effettuata, in maniera autonoma dallo switch o sotto ordine del controller, deve essere riferita al controller. In alcuni casi, questa operazione risulta vitale. Sempre secondo specifica, infatti, alla eliminazione di una porta, i flussi ad essa diretti non vengono modificati. Così facendo ci troveremmo ad avere, all’interno delle tabelle, un grosso quantitativo di flussi sporchi e non coerenti, oltre al fatto che realizzando una nuova porta con la stessa numerazione, ci troveremmo già dei flussi non richiesti che operano su di essa. L’operazione di mantenimento della coerenza dei flussi e della pulizia viene demandata al controller !

PIPELINE
Dopo tutte queste trattazioni architetturali andiamo finalmente a confrontarci con i meccanismi che ci permetto di lavorare davvero sul traffico. Ovviamente, anche qui non ci troveremo nessun vecchio amico tra i piedi (vedi spanning tree, protocolli di routing o chicchessia), ma troveremo altri validi alleati.

Il traffico che arriva ad uno switch OpenFlow viene veicolato in due canali, o pipeline, attraverso i quali viene elaborato. Queste due pipeline rappresentano un canale per il traffico entrante, e uno per il traffico uscente, chiamate rispettivamente Ingress processing e Egress processing

La pipeline in uscita è stata introdotta proprio con la versione 1.5.1 di OpenFlow, ed è considerata opzionale. L’elaborazione viene gestita da una serie di tabelle chiamate Flow Table. All’interno di queste tabelle vi sono delle regole, chiamate Flow Entry, a cui viene legato un Instruction Set, ossia un insieme di azioni che dovranno essere effettuate al matching con la specifica Flow Entry. Queste istruzioni possono andare a costruire e modificare un insieme di azioni, chiamato appunto Action Set, Il quale, a conclusione della pipeline, viene eseguito applicando le elaborazioni sul traffico.

(Figura tratta da OpenFlow® Switch Specification 1.5.1)
Ma andiamo a vedere esattamente cosa succede. Appena un pacchetto arriva nello switch da una qualsiasi porta di ingresso, viene inserito nella pipeline di ingresso (Ingress processing). In questa pipeline si possono costituire una o più Flow Table. Il traffico entrerà sempre nella prima tabella, che viene denominata come "0". La Flow Table è fondamentalmente un contenitore astratto, in cui raggruppare diverse Flow Entry. Si può dire che il lavoro effettivo di elaborazione dei pacchetti venga fatto dalle Flow Entry

Alla fine di ogni Flow Table, è possibile definire anche una Flow Entry speciale chiamata Table-miss, che ha lo scopo di gestire i pacchetti che non hanno avuto alcun matching. La struttura di queste Flow Entry è riportata nella figura seguente.

(Figura tratta da OpenFlow® Switch Specification 1.5.1)
Ogni Flow Entry è costituita da un insieme di 7 elementi:
  • Match Fields: la parte dell'insieme in cui si specificano le caratteristiche che deve avere il pacchetto.
  • Priority: stabilisce una precedenza tra le Flow Entry.
  • Counters: un contatore per le hit sulla Flow Entry.
  • Instructions: stabiliscono l’elaborazione da eseguire sul pacchetto.
  • Timeouts: il tempo massimo di vita della specifica riga.
  • Cookie: può essere usato per elaborazioni statistiche interne al protocollo OpenFlow.
  • Flags: possono modificare la gestione di una Flow Entry.


Una Flow Entry è identificata in maniera univoca dai primi due campi: Match Fields e Priority. Andiamo a vedere più nel dettaglio alcuni di questi elementi. 
  • Uno dei campi più importanti è sicuramente il Match Fields. Qui vengono definiti i parametri per cui un pacchetto appartiene o no ad una determinata Flow Entry. Questi parametri sono importanti poiché ci permettono di determinare cosa filtrare, come e con che granularità. In questo campo possono essere determinati fino a 44 diversi parametri, con i loro rispettivi valori. Un pacchetto viene considerato appartenente ad una Flow Entry se e solo soddisfa tutte le condizioni specificate nel campo Match Fields, (NOTA: questo non significa che le condizioni riguardino tutti i 44 parametri, ma possono essere solo su alcuni di questi). Vediamo alcuni di questi parametri:
Porta di input dello switch
Indirizzo Ethernet destinazione 
Indirizzo Ethernet sorgente 
VLAN ID
Indirizzo IPv4 sorgente/destinazione 
Indirizzo IPv6 sorgente/destinazione 
Porta UDP sorgente/destinazione   
ARP sorgente/destinazione IPv4   
ARP sorgente/destinazione IPv6     
ARP sorgente/destinazione MAC  
MPLS label
TCP flag
Code ICMP
Type ICMPv6
...
  • In caso di matching sovrapposti su due Flow Entry distinte, viene presa in esame la Priority. Come è facile immaginare, con questo valore si stabilisce una priorità in valore assoluto di quale Flow Entry abbia la precedenza su un'altra. Viene rappresentata da un valore numerico di 2 byte (da 0 a 65.535). Al valore maggiore corrisponde una maggiore priorità.
  • Determinata a quale Flow Entry appartiene un pacchetto, viene incrementato il valore del campo Counter della Flow Entry.
  • A questo punto si eseguono le Instruction contenute nel rispettivo campo. Qui è possibile operare in diversi modi: è possibile ad esempio effettuare modifiche al pacchetto, inoltrarlo verso un'altra Flow Table, modificare il suo Action Set o lavorare su dei metadati. Alcune di queste non devono necessariamente essere implementate sul switch OpenFlow (la modifica al pacchetto, ai metadati e altre). Per quanto riguarda l'invio ad altre Flow Table, è necessario specificare un paio di regole importanti: non è mai possibile far tornare un pacchetto in una Flow Table precedente e, come conseguenza, le Flow Entry dell'ultima tabella non potranno mai inviare il pacchetto ad un'altra tabella. La gestione dell'Action Set è fondamentale in questa fase, in quanto all'interno di questo insieme vengono accumulate tutte le elaborazioni da effettuare sul pacchetto, prima di concludere il suo percorso all'interno della pipeline.
Dopo tutto il percorso attraverso Flow Table e Flow Entry, è finalmente giunto il momento per il pacchetto di confrontarsi con l'Action Set. Questo insieme, attraversando la pipeline, è stato incrementato, decrementato e ripulito nel numero di volte stabilito dalle Instruction presenti nelle Flow Entry. Le azioni devono essere applicate al pacchetto in un ordine stabilito a monte, a prescindere dal loro inserimento nell'insieme. 
  1. copy TTL inwards 
  2. pop 
  3. push-MPLS 
  4. push-PBB 
  5. push-VLAN 
  6. copy TTL outwards 
  7. decrement TTL 
  8. set 
  9. qos 
  10. group
  11. output
Vediamo che tra le azioni eseguibili ci sono la manipolazione del TTL, il pop e il push di alcune tipologie di tag (VLAN, MPLS...), e soprattutto l'inoltro del pacchetto in uscita (group o output).


CONCLUSIONI
Siamo quindi arrivati in fondo a questa volata sul protocollo e sullo switch OpenFlow. Abbiamo familiarizzato un po' con i concetti e con l'ultima specifica disponibile.  Già da questa breve trattazione tecnica, è possibile capire quelli che sono i principi e gli obiettivi che guidano lo sviluppo di OpenFlow

Lo sviluppo procede, ma le implementazioni languono. Vedremo se OpenFlow riuscirà a far breccia nei nostri cuori o rimarrà quel lontano cugino con cui giocavamo a calcetto da piccoli, ma che non abbiamo mai più visto.

Altri approfondimenti ed altre analisi potrebbero ancora essere fatte, ma le lasciamo ad eventuali futuri post.

2 commenti:

  1. Se OpenFlow può leggere/modificare campi quali Mac Address, IP e TTL, è possibile utilizzare uno switch OpenFlow come router?

    RispondiElimina
    Risposte
    1. Assolutamente si. In effetti il nome OpenFlow Switch fuorvia un po'. In realtà il termine "switch" andrebbe inteso, non come sinonimo di layer 2, ma nel senso più largo, ovvero smistare. Tecnicamente può smistare dati di qualsiasi tipo. I limiti che ci vengono imposti riguardano solo la tipologia di campi su cui fare match (determinata ferreamente dal protocollo) e le elaborazioni che vi si possono effettuare direttamente, senza cioè passare dal controller esterno.

      Elimina