KVM and the network

tech_network

Nei miei precedenti post riguardanti il tema della virtualizzazione uno degli argomenti che sono solo stati accennati è quello della configurazione della rete.

In questo post andremo a vedere in quali modi è possibile configurare la rete e quali feature offre ogni tipologia proposta, quanto segue è stato testato con la versione modificata di QEMU per KVM su di una Ubuntu. Ovviamente il tutto resta valido anche per le Debian, nel caso in cui si utilizzino altre distribuzioni i concetti illustrati vanno adattati al caso specifico.

La prima tipologia di rete che andremo ad analizzare è la user networking. Successivamente analizzeremo la bridged networking, di quest’ultima tipologia vedremo tre esempi, ogni esempio si adatta ad un contesto applicativo diverso.

Ricordatevi in tutti i casi di verificare di aver caricato i moduli necessari (kvm-amd oppure kvm-intel oppure kqemu), nel caso vogliate, potete verificarlo con lsmod.

User networking

Questa tecnica consente di utilizzare una rete privata virtuale creata da QEMU per dare l’accesso alla rete al nostro guest.

E’ senza dubbio il metodo più semplice fra quelli disponibili, bisogna però tenere in considerazione che in questo caso non sarà possibile raggiungere dall’esterno della rete privata il guest a meno di usare l’opzione -redir, bisogna anche ricordare che alcuni protocolli di rete, come ad esempio ICMP, potrebbero non funzionare correttamente.

Dimenticavo: visto che ad ogni guest corrisponde una rete privata virtuale non è necessario specificare un mac address diverso per ogni guest. Ovviamente sul sistema operativo guest è necessario avere tutti i tool ed i driver necessari per la configurazione della rete  e per acquisire un indirizzo IP dinamicamente.

Per utilizzare questa caratteristica da QEMU è necessario aggiungere le opzioni -net nic -net user alla riga di comando che avvia il nostro guest, il seguente potrebbe essere un esempio:

sudo qemu-system-x86_64 -drive file=./lennybox.img,if=virtio,boot=on -net nic,model=virtio -net user -k it -localtime -smp 2 -m 512

Bridged networking

Se dall’esterno della rete si vuole contattare direttamente il guest senza voler attraversare il NAT di QEMU, se non si vuole avere alcun problema con con ICMP ed altri protocolli di rete a basso livello e soprattutto, se volete che la vostra macchina virtuale sia raggiungibile come qualsiasi altro host della vostra rete, allora questa è la modalità che fa per voi.

Per inciso: è la tipologia indicata nell’immagine ad inizio post, l’immagine è una mia personale rielaborazione da documentazione VMware.

A seconda dell’uso che intendete fare della macchina (virtualization server, uso saltuari della virtualizzazione, ecc…) potreste voler scegliere diverse tecniche implementative di questa tipologia di rete.

Soluzione A

Nel caso in cui facciate un uso saltuario di questo virtualizzatore potreste voler configurare un bridge “al volo” dalla vostra attuale configurazione di rete, in questo modo evitate il decadimento di prestazioni risultante dall’uso del bridge software. Per prima cosa andiamo ad installare i programmi necessari alla gestione del bridge:

sudo apt-get install bridge-utils

Come probabilmente avrete notato QEMU quando si usa l’opzione -net tap di default cerca di eseguire degli script di configurazione dell’interfaccia tunnel, questi script sono /etc/qemu-ifup all’avvio e /etc/qemu-ifdown alla chiusura. In essi è possibile inserire i comandi per la configurazione del bridge al volo.

Di seguito un esempio dei suddetti script:

paolomargara@mrcrow:~$ cat /etc/qemu-ifup
#!/bin/sh
eth="eth0"
br="br0"

/usr/sbin/brctl addbr $br
/sbin/ifconfig $eth 0.0.0.0 promisc up
/sbin/ifconfig $1 0.0.0.0 up
/usr/sbin/brctl addif $br $eth
/usr/sbin/brctl addif $br $1
/sbin/dhclient $br

Questo script assembla un bridge per l’utilizzo con QEMU. Le operazioni da svolgere in sostanza sono:

  1. creazione del bridge
  2. impostare l’interfaccia di rete in modalità promiscua
  3. creazione del’interfaccia tunnel $1 (tipicamente tap[0-9])
  4. aggiunta dell’interfaccia di rete e dell’interfaccia tunnel al bridge
  5. acquisizione da parte del bridge di un’indirizzo di rete (nel caso in oggetto l’indirizzo dell’interfaccia di rete è assegnato dinamicamente)
paolomargara@mrcrow:~$ cat /etc/qemu-ifdown
#!/bin/sh
eth="eth0"
br="br0"

/sbin/ifconfig $1   down
/sbin/ifconfig $eth down
/sbin/ifconfig $br  down
/usr/sbin/brctl delif $br $eth
/usr/sbin/brctl delif $br $1
/usr/sbin/brctl delbr $br
/sbin/dhclient $eth

Questo script disassembla il bridge creato all’avvio del programma e ripristina la configurazione della rete pre-esistente. Ora non resta che avviare la nostra macchina virtuale con un comando simile al seguente:

sudo qemu-system-x86_64 -drive file=./lennybox.img,if=virtio,boot=on -net nic,model=virtio -net tap -k it -localtime -smp 2 -m 512

Soluzione B

Questa soluzione prevede la configurazione di un bridge in /etc/network/interfaces in modo che all’avvio la rete sia già configurata in modalità bridged, è particolarmente indicata in quei casi in cui si fa un uso intensivo della virtualizzazione, come ad esempio in un virtualization server.

Per prima cosa andiamo ad installare i programmi necessari:

sudo apt-get install bridge-utils

Per la configurazione gli step da seguire sono:

  • Disattivate la vostra interfaccia di rete (un ifdown eth0 eseguirà tutto il lavoro)
  • Procedere con la configurare del bridge modificando nel seguente modo il file /etc/network/interfaces
auto lo
iface lo inet loopback 

auto br0
iface br0 inet dhcp
	bridge_ports eth0
	bridge_stp off
	bridge_maxwait 5
  • Terminato avviate il bridge con ifup br0

Col sistema così configurato gli script di configurazione della rete diventano i seguenti:

::::::::::::::
/etc/qemu-ifdown
::::::::::::::
#!/bin/sh 

switch=$(/sbin/ip route list | awk '/^default / { print $5 }')
/sbin/ifconfig $1 down
/usr/sbin/brctl delif ${switch} $1
::::::::::::::
/etc/qemu-ifup
::::::::::::::
#!/bin/sh

switch=$(/sbin/ip route list | awk '/^default / { print $5 }')
/sbin/ifconfig $1 0.0.0.0 up
/usr/sbin/brctl addif ${switch} $1

Nel caso in cui abbiate problemi in fase di connessione alla rete, cioè nel caso in cui il vostro kernel faccia ethernet filtering, aggiungete le seguenti linee nel file /etc/sysctl.conf

net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0
net.bridge.bridge-nf-filter-pppoe-tagged=0
net.bridge.bridge-nf-filter-vlan-tagged=0

…a questo punto riavviare o digitare alla console sysctl -p. Il comando è valido anche per mostrare i valori correntemente settati.

Nel caso in cui stiate utilizzando il NetworkManager occorre comunicargli di non gestire la scheda di rete utilizzata dal bridge, la versione modificata per Debian e Ubuntu del suddetto programma è fatta in modo che se un’interfaccia è listata in /etc/network/interfaces quella data interfaccia non viene gestita, quindi se per caso non volete rimuovere il NetworkManager dovete aggiungere le seguenti righe al file /etc/network/interfaces:

auto eth0
iface eth0 inet manual

Ora non resta che avviare la nostra macchina virtuale con un comando simile al seguente:

sudo qemu-system-x86_64 -drive file=./lennybox.img,if=virtio,boot=on -net nic,model=virtio -net tap -k it -localtime -smp 2 -m 512

Soluzione C

Questa soluzione è una variazione sul tema già trattato, offre gli stessi vantaggi che offre la soluzione B e in aggiunta permette di eseguire QEMU non come un processo dell’utente root, con tutto ciò che ne consegue, ma bensì con i privilegi di un utente qualsiasi con gli ovvi benefici a livello di sicurezza.

Per prima cosa andiamo ad installare i programmi necessari:

sudo apt-get install uml-utilities bridge-utils

Successivamente è necessario modificare un paio di regole di udev in modo che i due device utilizzati, /dev/kvm e /dev/net/tun, siano scrivibili da un determinato utente o da un determinato gruppo, io ho scelto di abilitare un determinato gruppo, di seguito le regole aggiunte e modificate:

::::::::::::::
/etc/udev/rules.d/60-kvmdrv.rules
::::::::::::::
KERNEL=="kvm", NAME="kvm", OWNER="root", GROUP="kvmusers", MODE="0660"
::::::::::::::
/etc/udev/rules.d/60-kvmnet.rules
::::::::::::::
KERNEL=="tun", NAME="net/%k", OWNER="root", GROUP="kvmusers", MODE="0660"
paolomargara@mrcrow:~$ tail -1 /etc/udev/rules.d/20-names.rules
#KERNEL=="tun",				NAME="net/%k"

Da notare che, affinché la regola contenuta nel file 60-kvmnet.rules funzioni come desiderato, è necessario modificare il file  20-names.rules commentando la regola riguardante il modulo tun.

Ovviamente è necessario creare il gruppo, in questo caso kvmusers, ed aggiungere l’utente che intendiamo utilizzare per l’esecuzione delle macchine virtuali al gruppo appena creato.

Successivamente è necessario creare un’interfaccia utilizzabile da un’utente tra i cui gruppi ci sia quello indicato nelle precedenti regole, impostarla come attiva ed andarla ad aggiungere al bridge creato come indicato nella soluzione B:

sudo tunctl -u paolomargara -t tap0
sudo ip link set tap0 up
sudo brctl addif br0 tap0

Infine avviare la macchina virtuale con un comando simile al seguente:

qemu-system-x86_64 -drive file=/media/sda5/lennybox.img,if=virtio,boot=on -net nic,model=virtio -net tap,ifname=tap0,script=no,downscript=no -k it -localtime -smp 2 -m 512

Per eliminare l’interfaccia tunnel non più necessaria potete utilizzare il comando sudo tunctl -d tap0.

Volendo potremmo sfruttare gli script di configurazione utilizzati nella soluzione B, previa aggiunta di sudo prima dei comandi che richiedono i privilegi di root, in modo da non dover digitare tutti i comandi necessari prima di eseguire QEMU.

::::::::::::::
/etc/qemu-ifdown
::::::::::::::
tap=$(echo $1|cut -f 1 -d ',')
switch=$(/sbin/ip route list | awk '/^default / { print $5 }')
/usr/bin/sudo /sbin/ip link set $tap down
/usr/bin/sudo /usr/sbin/brctl delif ${switch} $tap
::::::::::::::
/etc/qemu-ifup
::::::::::::::
/usr/bin/sudo /sbin/ip link set $1 up
/bin/sleep 1s
switch=$(/sbin/ip route list | awk '/^default / { print $5 }')
/usr/bin/sudo /usr/sbin/brctl addif ${switch} $1

Una piccola nota: nel file /etc/qemu-ifdown si è resa necessaria l’operazione di filtraggio sul parametro passato allo script per aggirare un baco che si è mostrato nella versione da me utilizzata. Normalmente non è necessario.

Potremmo quindi voler eseguire qualcosa di simile al seguente comando:

qemu-system-x86_64 -drive file=./lennybox.img,if=virtio,boot=on -net nic,model=virtio -net tap,ifname=$(sudo tunctl -b -u $(whoami)) -k it -localtime -smp 2 -m 512

…e per oggi è tutto! La prossima volta ricapitoleremo quanto visto fin’ora e vedremo come impostare, con appositi script, l’avvio di alcune macchine virtuali direttamente al boot del sistema.

Related post:

2 Comments

  1. Timothy says:

    Dall’immagine credevo che l’articolo trattasse vde e non queste cose da niubbi 🙂
    Che poi è la stessa cosa che fa lo script di defaut (ls /etc/kvm/*)

    • MRG says:

      Guarda che quando compili dai sorgenti gli script di gestione della rete te li devi scrivere tu… 😉
      Nel caso in cui tu stia utilizzando la versione fornita nel pacchetto della tua distribuzione non credo faccia male sapere cosa fanno gli script forniti…anzi.