Scuola Politecnica e delle Scienze di Base
Corso di Laurea in Ingegneria Informatica
Elaborato finale in Sistemi Operativi
Kernel-Based Virtual Machine
Anno Accademico 2013/2014
Candidato:
Luigi Gallo
matr. N46001138
Indice
Indice .................................................................................................................................................. III
Introduzione ......................................................................................................................................... 4
Capitolo 1: Introduzione alla Virtualizzazione .................................................................................... 5
1.1 Tecniche di Virtualizzazione ..................................................................................................... 6
1.2 Estensioni di Virtualizzazione per architetture x86 ................................................................... 7
Capitolo 2: Kernel-Based Virtual Machine ......................................................................................... 9
2.1 Architettura Generale ................................................................................................................. 9
2.2 KVM: gestione della memoria ................................................................................................. 11
2.2.1 Richiami di gestione della memoria.................................................................................. 11
2.2.2 Virtualizzazione della memoria in KVM .......................................................................... 12
2.2.3 Traduzione da indirizzo guest ad indirizzo host ............................................................... 13
2.2.4 Extended Page Tables e Rapid Virtualization Indexing ................................................... 15
2.2.5 MMU Notifiers ................................................................................................................. 17
2.3 KVM: gestione dell’Input/Output ............................................................................................ 18
2.3.1 Richiami di gestione dell’Input/Output............................................................................. 18
2.3.3 Input/Output Para-virtualizzato......................................................................................... 20
2.3.4 Input/Output con hardware assistance ............................................................................. 21
2.4 Altre funzionalità di KVM ...................................................................................................... 23
Capitolo 3: Virt-IO ............................................................................................................................. 27
3.1 VirtIO: cenni implementativi ................................................................................................... 29
Conclusioni ........................................................................................................................................ 31
Bibliografia ........................................................................................................................................ 32
Kernel-Based Virtual Machine
Introduzione
Grazie alla diffusione di hardware sempre più potente, in grado di far eseguire più sistemi
operativi in maniera concorrente, si diffondono di conseguenza le tecnologie software in
grado di sfruttarlo a pieno. Tra queste vi è la Virtualizzazione.
In questo elaborato di tesi verrà presentato uno dei progetti liberi più diffusi nel campo
della virtualizzazione: Kernel-Based Virtual Machine (KVM).
In un breve capitolo introduttivo saranno discussi prima i concetti di base della
virtualizzazione, soffermandoci sulle differenze tra le varie tecniche esistenti e su ciò che
ha permesso lo sviluppo di KVM; successivamente passeremo alla trattazione specifica di
KVM: i principi basilari, la sua architettura generale, come si propone di gestire la
memoria delle macchine virtuali, come si propone di gestire le operazioni Input/Output,
ed alcune delle funzionalità secondarie.
La trattazione si chiude con la presentazione di VirtIO: sistema supportato da KVM per
l’I/O Virtualization,
4
Kernel-Based Virtual Machine
Capitolo 1: Introduzione alla Virtualizzazione
Utilizzare un sistema informatico per emularne un altro similare, è l’idea che è alla base
della Virtualizzazione.
La Virtualizzazione ha origini ben radicate, ed esiste quasi da quando esistono i computer:
si è capito da subito che in questo modo si sarebbe potuto svolgere in maniera più sicura, o
migliore, molte operazioni che eseguono i computer generalmente. Questo ci è
testimoniato dal documento scientifico "Survey of Virtual Machine Research" di Goldberg
del 1974 [1], il quale già allora esprimeva le potenzialità di questa tecnica e prevedeva
alcuni sviluppi che negli anni a venire effettivamente sono stati realizzati.
Tecnicamente, per Virtualizzazione si intende l’astrazione delle risorse hardware di un
calcolatore costruendo in questo modo una Macchina Virtuale sulla quale è possibile
istallare ed eseguire Sistemi Operativi ed altro software.
Come prima peculiarità di questo tipo di tecnologie vi è la
possibilità di utilizzare più macchine virtuali sulla stessa
macchina fisica. Ognuna di esse avrà il suo ambiente
operativo separato dagli altri, agendo così in totale
sicurezza. L’hardware effettivamente necessario è dunque
utilizzato a pieno: si riducono costi di acquisto e di
alimentazione.
Figura 1: virtualizzazione delle
risorse
5
Kernel-Based Virtual Machine
I vantaggi apportati dall’utilizzo di questo tipo di tecnologie sono innumerevoli, sia per
architetture desktop, e ancor di più per architetture Server: di solito, per ragioni di
sicurezza, si riteneva opportuno eseguire una singola applicazione su una singola
macchina fisica.
La trasformazione Physical-to-Virtual (P2V) ha stravolto queste credenze, abbattendo il
sovradimensionando dei server e portando a grosse riduzioni di costi.
La Virtualizzazione è ritenuta vantaggiosa anche in fase di sviluppo e debugging:
ispezionare, controllare e configurare una macchina virtuale è molto più semplice in
confronto alle macchine fisiche.
Anche in fase di testing vi è maggiore comodità, in quanto eventuali errori riscontrati non
inficiano sull’integrità delle altre macchine virtuali e del sistema ospitante.
La portabilità e la duplicazione di macchine virtuali, infine, ci permettono di migrarle su
un’altra macchina ospitante o di possederne una copia di backup in un certo stato.
Il componente centrale di un sistema basato sulla virtualizzazione è l’Hypervisor.
L’Hypervisor, o Virtual Machine Monitor (VMM), ha il compito di gestire la coesistenza
di una o più macchine virtuali sulla stessa macchina fisica; il suo operato deve essere
trasparente alle macchine virtuali e soprattutto non deve aggiungere eccessivo overhead
alle operazioni, in modo da non pesare sulle prestazioni dell’intero sistema.
1.1 Tecniche di Virtualizzazione
La virtualizzazione può essere implementata utilizzando una delle seguenti tre tecniche:
Full-Virtualization, Para-Virtualization, Hardware-Assisted Virtualization. [2]
Esse differiscono profondamente tra loro, e in linea di principio non si può dire quale sia la
migliore in quanto le prestazioni dipendono fortemente dal tipo di carico di lavoro e quindi
dalla particolare applicazione in cui vengono utilizzate.
La Full-Virtualization è la tecnica di virtualizzazione attualmente più diffusa , compatibile
6
Kernel-Based Virtual Machine
con tutti i sistemi operativi. Esegue il codice utente direttamente sulla CPU fisica, ed
effettua una traduzione binaria di quelle istruzioni non virtualizzabili del kernel con altre
che hanno l’effetto desiderato sull’Hardware virtuale. Il Virtual Machine Monitor
provvede a fornire ad ogni macchina virtuale tutti i servizi di un sistema fisico, quali BIOS
virtuale, dispositivi virtuali, gestione della memoria virtuale. Questa tecnica consente di
disaccoppiare completamente il sistema operativo Guest dall’Hardware fisico, in modo da
tenerlo completamente allo scuro della virtualizzazione sottostante. Non è richiesta, per
questo motivo, alcuna modifica ai sistemi operativi Guest.
La Para-Virtualization invece risolve le criticità della virtualizzazione modificando il
Kernel del sistema operativo. Sostituisce le istruzioni non virtualizzabili del Kernel, con
Hypercall che comunicano con l’Hypervisor. Vi sono apposite API che risolvono i
problemi di gestione della memoria, gestione dell’I/O e gestione delle interrupt. Questa
tecnica è meno diffusa rispetto alla Full-virtualization perché produce un guadagno in
prestazioni solo in alcuni ambiti e per alcuni carichi di lavoro; inoltre soffre di una scarsa
compatibilità con alcuni sistemi operativi.
La Hardware-Assisted Virtualization, infine, è la più moderna delle tre ed è quella che
approfondiremo maggiormente poiché è strettamente correlata a KVM. Questa tecnica già
da adesso tiene testa alla più collaudata Full-Virtualization, ma si pensa che per il futuro
possa sostituirla completamente.
1.2 Estensioni di Virtualizzazione per architetture x86
Ciò che ha permesso lo sviluppo di KVM è stato, da parte dei fornitori dei processori con
architetture x86 (e.g. , Intel, AMD), l’aggiunta delle estensioni di virtualizzazione
all’instruction set.
Senza di esse è noto come fosse difficile la virtualizzazione con hardware x86, e proprio
per l’importanza che essa sta acquisendo negli ultimi anni, Intel e AMD hanno lavorato in
questo senso.
Tali estensioni prendono il nome di Intel VT-x e AMD-V, e sono in dotazione a tutti i
7
Kernel-Based Virtual Machine
processori di ultima generazione.
Questo nuovo instruction set ha di fatto aggiunto alle già esistenti Kernel Mode e User
Mode, la Guest Mode: una modalità operativa del processore con tutti i normali privilegi.
Codice proveniente da macchine virtuali, che sia codice di applicazioni o codice
privilegiato, esegue in questa particolare modalità. La particolarità è che il software di
sistema può richiedere di bloccare selettivamente delle istruzioni o l’accesso a particolari
registri.
Quando vi è uno switch verso la Guest Mode, o di ritorno dalla Guest Mode, avviene un
cambio nei registri di controllo, tra cui l’instruction pointer. Inoltre quando per mezzo di
uno switch si esce dalla Guest Mode, l’hardware tramite un report segnala il motivo di
questo switch. A raccogliere questa segnalazione vi è l’Hypervisor, che esegue in Kernel
Mode, e può intraprendere le azioni necessarie per permettere l’ eventuale ripresa della
Guest Mode.
In questo modo non c’è necessità di tradurre codice, e si risolvono a livello Hardware
alcune problematiche della Virtualizzazione, semplificando dunque i Virtual Machine
Monitor. Ne consegue un guadagno in prestazioni.
Il supporto Hardware fornito da queste estensioni, come vedremo nel prossimo capitolo, è
di estrema utilità per i Virtual Machine Monitor anche per la gestione della memoria e la
gestione dell’I/O.
KVM dunque esegue una virtualizzazione completa, servendosi fortemente dell’assistenza
dell’Hardware.
8
Kernel-Based Virtual Machine
Capitolo 2: Kernel-Based Virtual Machine
Kernel-based Virtual Machine (KVM) è una soluzione oper source alla virtualizzazione,
che aggiunge un Hypervisor perfettamente integrato nel kernel Linux.
Permette la creazione e l’esecuzione di una o più macchine virtuali che si integrano
perfettamente con il resto del sistema, e vengono viste come normali processi Linux.
L’idea di base è di far eseguire codice proveniente da macchine virtuali direttamente sulla
CPU fisica.
KVM necessita inoltre di un emulatore QEMU (Quick EMUlator), in versione modificata,
il quale si preoccupa dell’ effettiva “costruzione” della macchina virtuale.
2.1 Architettura Generale
KVM si compone di un modulo kernel di base kvm.ko, che fornisce l’infrastruttura
principale alla virtualizzazione; inoltre, è dotato di altri due moduli specifici, kvm-intel.ko
in riferimento all’estensioni di virtualizzazione fornite da Intel, e kvm-amd.ko per quelle di
AMD. [3]
KVM gode di un’ampia compatibilità con l’hardware, e di una grossa robustezza,
derivante proprio dal fatto che utilizza a pieno i moduli di un sistema ben collaudato quale
è il kernel Linux. Nell sviluppo di KVM, ci si è concentrati molto più sulle criticità
dell’hypervisor, delegando al sistema operativo Linux e all’Hardware il “lavoro sporco”
(e.g. scheduling, I/O).
Questo tipo di approccio si crede possa essere la forza di questo prodotto open source che
9
Kernel-Based Virtual Machine
rischia di affermarsi anche a dispetto di piattaforme proprietarie.
KVM è strutturato come un tipico device a caratteri in Linux: il suo device node è
/dev/kvm, e viene utilizzato per creare ed eseguire macchine virtuali tramite l’utilizzo di
system call di input/output control, ioctl().
Le operazioni messe a disposizione sono:
 creazione di una macchina virtuale;
 allocazione di memoria per una macchina virtuale;
 lettura e scrittura di registri di CPU virtuale;
 iniezione di una interrupt in una CPU virtuale;
 esecuzione di una CPU virtuale.
L’esecuzione di una CPU virtuale richiede di fatto l’utilizzo della Guest Mode.
Figura 2: ciclo Guest mode [3]
10
Kernel-Based Virtual Machine
Come mostrato in figura, l’esecuzione Guest avviene in un ciclo passando per le tre
modalità User, Kernel e poi Guest: al livello più esterno vi è la chiamata di una system call
affinchè si possa eseguire codice Guest. L’esecuzione si arresterà solo a causa di eventuali
istruzioni di I/O, o per altri eventi esterni quali l’arrivo di pacchetti di rete o altri tipi di
interrupt.
A livello Kernel invece si “forza” il processore ad entrare in Guest Mode, con la quale si
esegue codice proveniente da macchine virtuali. In seguito, all’uscita dalla Guest Mode, si
eseguono le operazione necessarie alla ripresa dell’esecuzione; queste dipendono
ovviamente dalla motivazione per cui si è usciti dalla Guest Mode.
2.2 KVM: gestione della memoria
La memoria centrale è uno dei componenti più importanti di un calcolatore, e pertanto il
suo grado di ottimizzazione pesa molto sulle prestazione di tutto il sistema. Considerazioni
analoghe, se non ancora più forti, si possono fare per le macchine virtuali. Per
comprendere a pieno come KVM virtualizza la memoria richiamiamo velocemente
concetti di gestione della memoria in ambito non virtualizzato.
2.2.1 Richiami di gestione della memoria
Nei moderni sistemi operativi, i programmi utente lavorano con indirizzi logici (virtuali)
di memoria, che saranno poi tradotti in indirizzi fisici di memoria con il supporto hardware
del Memory Managment Unit (MMU). Il lavoro dell’MMU è affiancato dal Translation
Lookaside Buffer (TLB), che è una memoria associativa che effettua attività di caching.
Linux ha una gestione della memoria paginata, non segmentata, con livelli di paginazione
e diverse dimensioni delle pagine, per permettere la portabilità.
Il processo è “ingabbiato” nel suo spazio di indirizzamento: non vede dati/istruzioni di
altri processi, dati/istruzioni del sistema operativo e gli intervalli di indirizzi di I/O
11
Kernel-Based Virtual Machine
memory-mapped dei dispositivi.
L’unico modo che hanno per interagire con l’esterno è tramite il sistema operativo (e.g.
System call, risorse condivise). In questo modo si realizza la protezione delle risorse.
I processi possono richiedere l’allocazione di spazi di memoria con una system call, e la
memoria allocata viene aggiunta nella tabella delle pagine. Quando il processo accede ad
uno spazio di memoria, la pagina viene mappata sulla memoria fisica.
Il Kernel, per sua necessità, può rimuovere il mapping pagina-mem.fisica in qualunque
momento; quando il processo vi farà di nuovo accesso, si scatenerà un errore di Page Fault
e bisognerà mappare di nuovo la pagina.
2.2.2 Virtualizzazione della memoria in KVM
Le macchine virtuali di KVM sono viste come normali processi Linux, e dunque per
allocare memoria ad una di essa verrà effettuata una classica system call Malloc().
Se per esempio vogliamo che la macchina virtuale abbia una memoria fisica di 1GB,
KVM con una Malloc() le allocherà 1GB di spazio in memoria virtuale (intesa come
spazio di indirizzi logici). Questo spazio di memoria non verrà mappato in memoria fisica
al momento della Malloc(), ma soltanto quando il processo, e cioè la macchina virtuale, vi
farà effettivamente accesso.
Mostrando le macchine virtuali, al sistema ospitante Linux, come normali processi, si
ottiene automaticamente il risultato di disaccoppiare efficacemente gli ambienti operativi
delle macchine virtuali. Una macchina virtuale non può accedere a dati/istruzioni delle
altre macchine virtuali né del sistema ospitante.
La visione della memoria che ha una macchina virtuale è contigua ed esclusiva, come
fosse la sua memoria fisica.
12
Kernel-Based Virtual Machine
Figura 3: Memory Virtualization [3]
Sulle macchine virtuali eseguiranno i sistemi operativi guest, che attueranno le loro attività
di gestione della memoria; avranno le loro tabelle delle pagine guest ed i loro indirizzi di
memoria guest.
Bisogna in qualche modo sincronizzare le attività guest e le attività host, in modo che non
si invalidino tra loro.
2.2.3 Traduzione da indirizzo guest ad indirizzo host
In un sistema basato su virtualizzazione, in aggiunta alla traduzione da indirizzo virtuale a
indirizzo fisico, deve essere eseguita la traduzione da indirizzo guest ad indirizzo host. Se
volessimo concatenare semplicemente queste due traduzioni, eseguendole in sequenza ad
13
Kernel-Based Virtual Machine
ogni accesso in memoria, riscontreremmo grossi cali di prestazioni. Inoltre, in questo
modo il sistema operativo guest dovrebbe poter accedere alla tabella delle pagine acceduta
dall’Hardware fisico, violando così il principio per cui le macchine virtuali sono
totalmente disaccoppiate da esso.
La tecnica di base utilizzata da KVM è quella tipica dei più comuni sistemi basati su
virtualizzazione: la Shadow Page Tables. La tabella delle pagine utilizzata dall’hardware
è separata da quelle utilizzate dalle macchie virtuali.
Quando un guest KVM effettua un cambiamento nella sua tabella delle pagine, l’host
dovrà prontamente accorgersi di ciò, e a sua volta replicare il cambiamento nella reale
tabella delle pagine acceduta dall’hardware.
KVM è in grado di bloccare l’esecuzione della guest mode, quando il guest prova a settare
il registro CR3 che punta alla tabella delle pagine, grazie alle estensioni hardware messe a
disposizione dal processore. Ogni modifica di una entry nella guest page table, o
l’inserimento di una nuova entry, viene intercettata da KVM che replica la modifica nella
reale tabella delle pagine.
In linea di principio questo meccanismo funziona bene perché si evita di eseguire la
duplice traduzione, e può coesistere perfettamente con tutte le operazioni di gestione della
memoria eseguite dal sistema guest (per esempio i page fault). [4]
Figura 4: Shadow Page Tables [5]
14
Kernel-Based Virtual Machine
Nasce, però, l’esigenza di tenere sincronizzate le tabelle delle pagine guest e la shadow
page table: ogni modifica nella guest page table richiede più accessi in memoria, oltre che
ulteriore overhead introdotto dalla necessità di bloccare l’esecuzione guest ogni volta.
Ovviamente il problema si aggrava ulteriormente se pensiamo alla situazione in cui
coesistono più macchine virtuali, ognuna con le proprie CPU virtuali.
Il mantenimento di questa sincronizzazione costa un calo di prestazioni non trascurabile.
Per questo motivo lo sviluppo di KVM è andato avanti, per aggiungere la compatibilità
con le nuove estensioni Hardware per una gestione della memoria più efficiente.
2.2.4 Extended Page Tables e Rapid Virtualization Indexing
Per sovvertire a questo grosso calo di prestazioni Intel e AMD hanno proposto le proprie
soluzioni, entrambe basate sull’idea di effettuare la traduzione da guest physical address a
host physical address senza passare attraverso l’host page table.
Queste estensioni prendono il nome di Extended Page Tables (EPT)(Intel) e Rapid
Virtualization Indexing (RVI) (AMD, anche conosciute come Nested Page Tables,
NPT). Si permette al sistema operativo guest di gestire gli indirizzi guest, e di effettuare la
traduzione da indirizzo guest logico ad indirizzo guest fisico; non vi è alcuna
sincronizzazione con la tabella delle pagine host. EPT/RVI entra in gioco quando poi
bisogna ottenere l’indirizzo host fisico (definito anche machine address).
Figura 5: traduzione con EPT [10]
15
Kernel-Based Virtual Machine
Non entriamo nel dettaglio di come EPT/RVI effettuano questa traduzione essendo un
meccanismo esterno a KVM, ma ci interessa il principio di funzionamento di base e
quanto possa migliorare le prestazioni.
Per eseguire velocemente questa traduzione è stato definito un insieme di strutture
riconosciute dall’hardware: ci si affida ad un TLB più grande per tenere traccia anche
delle traduzioni richieste direttamente dalle macchine virtuali. Potranno tranquillamente
coesistere in questo “super” TLB voci provenienti da macchine virtuali diverse,
identificate con dei tag specifici della macchina virtuale.
Figura 6: EPT/NPT
Questo meccanismo soffre molto i TLB miss, i quali per essere risolti richiedono un
numero considerevole di accessi in memoria, e per questo è necessario un TLB abbastanza
grande per ridurli al minimo.
Con questa tecnica, KVM è esonerato dal compito di tradurre gli indirizzi guest: secondo
Intel le prestazioni possono migliorare addirittura del 48% [5].
16
Kernel-Based Virtual Machine
2.2.5 MMU Notifiers
Sia che trattasi di Shadow Page Tables o di EPT/RVI, abbiamo in qualche modo visto
come KVM può sincronizzare la gestione della memoria del sistema ospitante a valle di
una modifica nella memoria virtuale del sistema Guest. Cosa accade invece se la modifica
nativa avviene nell’host page table, e cioè nella reale memoria acceduta dall’Hardware?
Sappiamo che i sistemi operativi, ed in particolare Linux, attuano diverse attività di
gestione della memoria, a prescindere delle macchine virtuali (e.g. swapping, condivisione
di pagine, rilocazione). Queste attività possono invalidare le tabelle delle pagine guest
(oppure EPT/RVI), causando malfunzionamenti.
Si potrebbe, in linea di principio, pensare di evitare il problema settando come “pinned” le
pagine di memoria delle macchine virtuali sulla memoria fisica; cioè impedire, bloccare, le
operazioni di swapping su queste pagine. In questo modo staremmo in pratica impedendo
a tutta la gestione della memoria di usufruire dei grossi vantaggi della paginazione. Una
forzatura decisamente eccessiva.
MMU_Notifiers è la soluzione adottata da KVM per questo problema: ogni volta che
attività specifiche di gestione della memoria centrale riguardano spostamenti di pagine di
macchine virtuali, il kernel con una chiamata a mmu_notifier invalidate_page() invaliderà
la particolare entry nella guest page table (o struttura EPT/RVI). Sarebbe come notificare
la macchina virtuale dell’operazione. Successivamente, quando il Guest tenterà l’accesso a
queste aree di memoria, si bloccherà in un page fault, che sarà risolto nelle normali
modalità.
Esistono altre funzioni mmu notifier, ognuna per ogni particolare esigenza di gestione
della memoria; per esempio nel momento dell’allocazione di una nuova pagina di
memoria a vantaggio di una macchina virtuale, vi è la chiamata a mmu_notifier
change_pte() che provvede ad inserire la nuova entry nella guest page table (o struttura
EPT/RVI).
17
Kernel-Based Virtual Machine
2.3 KVM: gestione dell’Input/Output
La gestione delle operazioni di Input/Output di un sistema virtualizzato è il punto più
debole della virtualizzazione e in particolare di KVM. Per mezzo della grossa eterogeneità
delle periferiche, e della lentezza delle stesse in confronto alla velocità di esecuzione degli
altri componenti (e.g. CPU, memoria), l’ I/O è causa di cali di prestazioni anche in sistemi
non virtualizzati. Con l’overhead aggiunto dalla virtualizzazione, per macchine che
eseguono molte operazione di I/O (per esempio le macchine server), questo problema può
risultare un collo di bottiglia abbastanza critico.
Esistono diversi sistemi che virtualizzano l’I/O in modo efficiente, ognuno di essi
riconducibile ad uno dei seguenti tipi:
 Emulation of devices (Software)
 Para-virtualization (Software)
 Hardware Assistance
2.3.1 Richiami di gestione dell’Input/Output
La maggiore parte dei dispositivi di I/O sono estremamente lenti se comparati alla
memoria centrale. E’ necessario dunque mettere a punto tecniche che impediscono alle
operazioni di I/O di inficiare le prestazioni del sistema. Rendere efficiente l’I/O significa
rendere efficiente anche le altre componenti del sistema.
Le tecniche di riferimento sono:
 I/O programmato: il processo attende il completamento dell’operazione di I/O;
 I/O Interrupt-driven: il processo invoca un comando di I/O e si sospende, in modo
da liberare la CPU. Quando l’operazione è terminata il modulo di I/O invia
un’interrupt.
 Direct Memory Access (DMA): il sistema operativo invia al DMA la richiesta di
18
Kernel-Based Virtual Machine
I/O, con l’indirizzo del dispositivo e altre informazioni necessarie. Completato il
trasferimento, il DMA invia un’interrupt alla CPU.
Ogni periferica necessita di essere configurata prima dell’utilizzo; tutto il codice che
dipende dal dispositivo viene gestito dal driver del dispositivo. Il compito di un driver è di
accettare le richieste provenienti dal device-indipendent software e di controllare che
queste siano eseguite.
2.3.2 Schema di base di KVM
Figura 7: KVM, schema di I/O virtualization
Le richieste di Input/Output possono avere diversa natura (e.g. Programmed I/O, MemoryMapped I/O), ognuna di esse con la propria complessità nell’essere virtualizzate.
19
Kernel-Based Virtual Machine
Il compito di KVM quando trattasi di gestione dell’Input/Output è quello di intercettare le
richieste di I/O da parte del Guest OS, risolverle, ed emulare il comportamento dei
dispositivi. Trattasi infatti di Emulation of devices I/O Virtualization. Dal lato Host, deve
permettere l’iniezione di interruzioni nel sistema Guest.
KVM, per la risoluzione delle richieste di I/O necessita di uscire dalla guest mode.
Tutte le richieste di Input/Output vengono inoltrate allo userspace, ed eventualmente si
innesca una reale operazione di Input/Output (per esempio il trasferimento di un pacchetto
di rete). Al completamento dell’operazione vi sono meccanismi per iniettare l’interruzione
nel sistema guest.
Esistono particolari flag che segnalano quando il guest è pronto a ricevere l’interruzione.
Non è molto diffuso nel dettaglio come KVM risolva queste problematiche poiché spesso
si affiancano a KVM sistemi dedicati esclusivamente all’I/O, più sofisticati e nettamente
più efficienti (e.g. Virtio, capitolo 3).
2.3.3 Input/Output Para-virtualizzato
Un altro approccio che può essere utilizzato per le operazioni di Input/Output può essere
quello della Para-virtualizzazione. Le richieste di I/O da parte delle applicazioni che
eseguono nel sistema guest arrivano come di consueto ai driver guest; essi saranno delle
versioni modificate che invocheranno a loro volta, con le Hypercall, l’intervento
dell’Hypervisor. Utilizzando questo approccio, il Virtual Machine Monitor non si deve
preoccupare di intercettare le richieste di I/O, e di emulare il comportamento
dell’hardware, ma esse giungeranno autonomamente con la cooperazione dei driver.
20
Kernel-Based Virtual Machine
Figura 8: I/O Para-virtualization
Questo non è un banale risultato ottenuto, poiché alcune operazione di I/O, per esempio il
Memory-Mapped I/O, utilizza le stesse istruzioni di un normale accesso in memoria. C’era
quindi prima la difficoltà di riconoscere queste richieste e poi di virtualizzarle; il problema
non era di facile risoluzione.
La gestione delle richieste di I/O è uno degli ambiti in cui la Paravirtualizzazione può
funzionare meglio della Full-Virtualization. Questa combinazione di
Full-Virtualization con I/O Paravirtualizzato a volte viene definita Hybrid Virtualization.
2.3.4 Input/Output con hardware assistance
Per quanto riguarda l’ Hardware assisted I/O virtualization facciamo riferimento ad
architetture Intel.
21
Kernel-Based Virtual Machine
Intel® Virtualization Technology for Directed I / O (VT-d) è una ulteriore estensione delle
tecnologie di virtualizzazione (VT-x) fornite da Intel, e riguarda prettamente la
virtualizzazione dell’I/O.
Intel VT-d migliora la sicurezza, l’affidabilità e le prestazioni dei dispositivi di I/O in
ambiente virtualizzato, spingendo ancora oltre la virtualizzazione nella sua missione di
riduzione di costi e velocità produttiva[n].
Questa nuova tecnologia è implementata in Hardware, e consiste nell’aggiunta di un
DMA-remapping che si trova tra il DMA delle periferiche e la memoria fisica.
Questo nuovo componente ha il compito di far comunicare i dispositivi di I/O direttamente
con le macchine virtuali, in modo che il VMM non viene invocato ad ogni richiesta di I/O.
Intel VT-d consente al software di sistema di creare domini di protezione in memoria
fisica, che possono rappresentare memoria allocata ad una macchina virtuale oppure
allocata da un driver del sistema guest.
I dispositivi di I/O vengono assegnati a particolari domini di protezione, e ciò fornisce
l’isolamento necessario a garantire la protezione delle risorse di ogni macchina virtuale.
Quando un dispositivo tenta di accedere ad una particolare locazione di memoria, il DMAremapping verifica se il dispositivo è autorizzato ad accedere al particolare dominio
protetto; se non è autorizzato viene segnalato un errore al software di sistema.
Figura 9: DMA-remapping [8]
In questo modello i dispositivi di I/O sono assegnati direttamente alle macchine virtuali, e
22
Kernel-Based Virtual Machine
perciò possono comunicarci in maniera diretta. Quando vi è una richiesta di I/O da parte di
un driver del sistema guest non vi è l’invocazione del VMM. Il VMM esegue solo attività
di controllo al momento dell’assegnazione del dispositivo alla particolare macchina
virtuale.
E’ il driver del sistema guest a controllare il dispositivo. Sappiamo però che il sistema
operativo guest lavora con indirizzi guest, che saranno poi tradotti in indirizzi host. Nasce
dunque l’esigenza di eseguire questa conversione, ed è il principale compito del DMAremapping (da cui il nome “rimappatura”).
Il DMA-remapping è programmato dal VMM, che conosce le corrispondenze GPA-HPA
(indirizzo guest – indirizzo host), in modo che i dati vengano trasferiti direttamente sul
buffer appropriato del guest. Non vi è alcuna attività di emulazione da parte del VMM né
alcuna modifica nei driver del sistema guest.[8]
Figura 10: assegnazione diretta del dispositivo [8]
2.4 Altre funzionalità di KVM
KVM supporta molte funzionalità desiderabili nell’ambito della virtualizzazione.
23
Kernel-Based Virtual Machine
Uno dei motivi per cui la virtualizzazione ha preso piede nell’informatica moderna è la
possibilità di migrare le macchine virtuali su un altro sistema host: Live Migration.
KVM supporta la Live Migration senza interrompere
l’esecuzione della macchina virtuale durante il trasporto;
può essere considerata funzionante e connessa in rete
sempre, dato che risulta inattiva solo per poche decine di
millisecondi. Gli utenti che la utilizzano in maniera
remota, non si accorgeranno della rilocazione su un
diverso host fisico. La Live Migration funziona copiando
Figura 11: Live migration [6]
la memoria del guest sull’host d’arrivo della migrazione, in parallelo con l’esecuzione del
guest ancora sull’host di partenza; se una pagina di memoria viene modificata dopo la sua
copia sull’host d’arrivo, essa dovrà essere ricopiata. A questo proposito, KVM fornisce un
dirty page log per tener traccia delle pagine di memoria da ricopiare.
La Live Migration è utilizzata anche per copiare le macchine virtuali in un certo stato, per
possederne copie di buckup su un altro host fisico.
KVM supporta anche il Kernel SamePage Merging (KSM): un sistema che permette la
condivisione di pagine di memoria tra macchine virtuali.
Spesso in memoria vi sono pagine ridondanti per mezzo che ogni copia è riferita ad una
singola macchina virtuale. Con KSM si fa uno scanning della memoria delle macchine
virtuali, e qualora si trovino pagine identiche ne si fa l’unione in una singola pagina
condivisa tra due o più macchine virtuali. Se successivamente uno dei guest tenta di
modificare una pagina condivisa, otterrà la sua copia privata.
KSM è una funzionalità che KVM supporta in quanto facente parte del kernel Linux.
VirtIO mette a disposizione di KVM un driver specifico per il supporto al ballooning, e
cioè i guest KVM possono dinamicamente ridurre o incrementare la dimensione della
propria memoria. Questa funzionalità è utile a sostenere l’host KVM in caso di
24
Kernel-Based Virtual Machine
over-committing della memoria. Supponiamo di avere una macchina virtuale con una
memoria di 2GB; se per esempio sta utilizzando soltanto 1GB di memoria, potrebbe essere
utile cedere il GB restante all’host, in modo che possa assegnarlo ad un’altra macchina
virtuale oppure farne in ogni caso un utilizzo migliore.
Le operazioni principali implementate dal balloon driver sono quindi:
 Inflate: memoria viene ceduta dal guest all’host;
 Deflate: memoria viene ceduta dall’host al guest;
Figura 12: ballooning [9]
Non è sempre prevedibile come si distribuiscono sulle macchine virtuali i carichi di
lavoro, quindi avere la possibilità di concedere memoria aggiuntiva ad una macchina
virtuale sotto pressione, a svantaggio di un’altra al momento più libera, può aumentare la
produttività dell’intero sistema.
Inizialmente c’era
il problema che questa gestione dinamica dell’assegnazione di
memoria doveva essere fatta del tutto manualmente; doveva esserci qualcuno a monitorare
la situazione e decidere in che modo effettuare il ballooning.
Dato che questa funzionalità deve essere automatica per essere davvero utile, nelle ultime
versioni di KVM è stata aggiunta la automatic ballooning: i guest e l’host cooperano in
25
Kernel-Based Virtual Machine
modo che, se è possibile, nessuno vada sotto pressione con la memoria.
Sono definiti tre livelli di pressione della memoria, per ognuno dei quali i guest ritornano
all’host un certo numero di MB di memoria, in dipendenza al proprio livello di pressione
di memoria. [9]
Sia per la definizione dei livelli di pressione che per il numero di MB “restituiti”, ci sono
parametri da settare, modificabili anche a run-time. Il tuning di questi parametri è
importante per un corretto funzionamento dell’automatic ballooning, e dipende fortemente
dalla distribuzione dei carichi di lavoro sulle macchine virtuali.
La virtualizzazione sta aprendosi strada anche in ambito embedded. I benefici che esso
apporta, quali per esempio il semplice speed-up oppure la grossa comodità in fase di
sviluppo, debugging e testing, ha aperto il mercato degli hypervisor anche al mondo
embedded.
Le peculiarità di KVM si incastrano perfettamente con le necessità di questi ambiti: vasta
compatibilità con l’hardware, possibilità di emulazione di hardware fuori produzione,
compatibilità con tutti i sistemi operativi (anche Real Time OS), customizability,
semplicità. [11]
26
Kernel-Based Virtual Machine
Capitolo 3: Virt-IO
VirIO è uno standard di I/O virtualization per dispositivi (e.g. dischi, dispositivi di rete).
E’ la principale piattaforma di I/O Virtualization scelta da KVM per migliorare le
prestazioni di rete e le operazioni su disco delle macchine virtuali.
VirtIO si basa sul principio della Para-virtualizzazione, e cioè mette a disposizione un
insieme di API che permettono la collaborazione dell’Hypervisor con i driver modificati
del guest, per risolvere in modo efficiente le richieste di I/O delle macchine virtuali.
La sua implementazione si colloca in un modulo kernel nel guest, che rappresenta il frontend driver, e in un device di QEMU, che rappresenta il back-end driver.
Figura 13: VirtIO, comunicazione guest-host [7]
27
Kernel-Based Virtual Machine
Il front-end driver ha il compito di raccogliere le richieste di I/O che arrivano dai processi,
e di inviarle al back-end driver.
Il back-end driver accetta le richieste provenienti dal front-end driver ed esegue le
operazioni di I/O sull’hardware fisico.
L’effettiva comunicazione tra i due driver avviene tramite dei buffer di memoria condivisi
tra i guest e QEMU, che VirtIO chiama virtqueue. Ogni operazione di I/O richiede una o
più virtqueue per lo scambio dei comandi e per l’effettivo trasferimento dei dati.
Si crea, in questo modo, un canale di comunicazione diretto tra il guest e l’host. [7]
Figura 14: schema di I/O virtualization con VirtIO
Se confrontiamo lo schema di VirtIO (in figura) e lo schema di base di KVM, notiamo che
il flusso di dati giunge all’hardware, o dall’hardware, in maniera più diretta e veloce. Si
28
Kernel-Based Virtual Machine
noti che QEMU esegue nello spazio utente dell’host, quindi si entra in Kernel Mode
soltanto quando entrano in gioco i device driver dell’hardware fisico.
3.1 VirtIO: cenni implementativi
VirtIO è organizzato in 5 moduli driver, ognuno dedicato ad una specifica esigenza di I/O:
 virtio-blk, per i block devices (per esempio i dischi);
 virtio-net, per i dispositivi di rete;
 virtio-pcl, per l’emulazione di PCI;
 virtio-balloon, per il ballooning;
 virtio-console.
Ognuno di questi cinque moduli presenti nel front-end driver ha il suo corrispondente nel
back-end driver. Un device in Virtio è identificato da un oggetto virtio_device che, a
seconda del tipo di dispositivo, è gestito da uno dei cinque driver di VirtIO. Le operazioni
di configurazione del device sono implementate in un modulo virtio_config_ops; tra le
altre, vi è una funzione find_vq che ritorna le virtqueue associate ad uno specifico
virtio_device.
Le funzioni principali utilizzate per la comunicazione tra guest e QEMU sono le
virtio_queue_ops, ovvero le operazioni sulle virtqueue. La procedura generale prevede i
seguenti passi:
 Il guest chiama la add_buff, che rappresenta la richiesta di I/O; il guest invia le
informazioni necessarie per eseguire l’operazione di I/O e si aspetta i dati sul
buffer condiviso.
 Successivamente con la kick, il guest notifica l’hypervisor della nuova richiesta
inviatagli.
 Dal lato QEMU, con una pop si estraggono dalla coda le informazioni per eseguire
l’I/O.
 Completata l’operazione di I/O, con la push si caricano i dati sul buffer condiviso.
 Infine il guest chiama la get_buff per leggere i dati dal buffer condiviso. Il guest può
29
Kernel-Based Virtual Machine
chiamare questa funzione in polling, oppure aspettare la notifica di completamento
dell’operazione da parte di una funzione apposita della virtqueue. [7]
30
Kernel-Based Virtual Machine
Conclusioni
La trasformazione Physical-to-Virtual è ritenuta vantaggiosa in un numero di applicazioni
sempre maggiore, e per questo i sistemi capaci di effettuarla al meglio stanno
sviluppandosi sempre di più.
In un mondo come quello della Virtualizzazione, dove è richiesta compatibilità con altri
sistemi e continuo sviluppo di nuove funzionalità, Kernel-Based Virtual Machine
rappresenta un’importante apertura al mondo open source.
L’approccio utilizzato dagli sviluppatori, e cioè quello di non reinventare nulla di già
esistente, ha permesso a KVM di rimanere estremamente semplice. Questo approccio si
crede possa essere la forza di questo prodotto e che possa affermarsi anche a dispetto di
piattaforme proprietarie.
31
Kernel-Based Virtual Machine
Bibliografia
[1]
[2]
Robert P. Goldber, 1974, “Survey of Virtual Machine Research”
VMware, 2007, “Understanding Full Virtualization, Paravirtualization,
Hardware Assist”, http://www.vmware.com/files/pdf/VMware_paravirtualization.pdf
[3]
Proceedings of the Linux Symposium, 2007, KVM: the Linux Virtual Machine
Monitor, http://www.linux-kvm.com/sites/default/files/kivity-Reprint.pdf
[4]
“linux-kvm”, 17/11/2014, http://www.linux-kvm.org/page/Memory
[5]
VMware, 2009, “Performance Evaluation of Intel EPT
Hardware Assist”, http://www.vmware.com/pdf/Perf_ESX_Intel-EPT-eval.pdf
[6]
Red Hat, 2009, “KVM - Kernal-Based Virtual Machine”,
http://www.redhat.com/en/files/resources/en-rh-kvm-kernal-based-virtual-machine.pdf
[7]
[8]
IBM, 19/11/2014, http://www.ibm.com/developerworks/library/l-virtio/
Intel,
14/11/2014, https://software.intel.com/en-us/articles/intel-virtualization-
technology-for-directed-io-vt-d-enhancing-intel-platforms-for-efficient-virtualization-ofio-devices
[9]
Luiz Capitulino, 2013, “Automatic Ballooning”,
http://www.linux-kvm.org/wiki/images/f/f6/Automatic-ballooning-slides.pdf
[10] Sheng Yang, 2008, “Extending KVM with new Intel Virtualization technology”,
http://www.linux-kvm.org/wiki/images/c/c7/KvmForum2008$kdf2008_11.pdf
[11]
Jan Kiszk, 2010,” KVM in Embedded Requirements, Experiences, Open
Challenges”,
http://www.linux-kvm.org/wiki/images/f/f3/2010-kvm-forum-Embedded-
KVM.pdf
32
Kernel-Based Virtual Machine
33