Looking for Computer Science  & Information Technology online courses ?
Check my new web site: https://www.yesik.it !

User Mode Linux vous permet de créer des machines virtuelles Linux qui tournent en mode utilisateur sur votre machine réelle. Si pouvoir lancer une machine de manière isolée peut être utile, à un moment ou un autre, vous souhaiterez sans doute connecter une machine virtuelle User Mode Linux au réseau physique. Non seulement, c'est possible, mais il existe plusieurs manières de faire.

Ici, nous commencerons par créer un tunnel pour connecter la machine virtuelle à son hôte. Puis nous établirons un pont qui permettra de relier ce tunnel au réseau externe. Chose intéressante, ces techniques ne sont pas propres à UML – et peuvent être recyclées dans d'autres contextes.

Créer un tunnel

La première étape pour relier une machine virtuelle UML au réseau va être de créer un tunnel TUN/TAP. Il s'agit d'un pseudo-périphérique réseau connecté à un logiciel, plutôt qu'à une interface physique (carte réseau). C'est via ce tunnel TUN/TAP que UML communiquera avec l'hôte.

Installation

Sous Debian vous aurez besoin du paquet uml-utilities pour utiliser tunctl(8). Si ce logiciel n'est pas déjà sur votre machine utilisez le gestionnaire de paquets de votre distribution pour procéder à l'installation.

sh# apt-get install uml-utilities
sh# tunctl -g uml-net
Set 'tap0' persistent and owned by gid 117

La commande tunctl permet de préciser quels sont les utilisateurs qui auront accès au tunnel. Ici, j'utilise l'option -g qui permet de préciser que seuls les membres du groupe uml-net y auront accès. Sous Debian, ce groupe a été créé automatiquement lors de l'installation du paquet uml-utilities.

Piège:

Pensez aussi à ajouter à ce groupe les utilisateurs autorisés à utiliser le tunnel:

sh# useradd sylvain uml-net

Et n'oubliez pas que la modification des groupes d'un utilisateur n'est prise en compte qu'au login. Si vous êtes déjà connecté, il faudra vous déloguer puis vous reloguer.

Monter un pont

Pont Linux.png

Pont Linux — Une machine Linux peut être configurée pour servir de pont. Cela permet d'interconnecter au niveau Ethernet plusieurs interfaces réseau. Dans l'exemple ci-dessus, le pont br0 interconnecte les réseaux reliés aux interfaces eth0, tap0 et tap1. Les trames Ethernet peuvent donc être acheminées entre ces interfaces – exactement comme entre les ports d'un switch. Au niveau IP, seul le pont possède une adresse.

A ce stade, votre hôte est relié au réseau par une interface physique (eth1 dans mon cas), et à un tunnel tuntap via l'interface tap0. Mais ces deux interfaces ne sont pas interconnectées!

Dans le monde physique, pour résoudre ce problème, vous utiliseriez sans doute un switch. L'équivalent dans Linux est un pont (bridge).

La création et la configuration d'un pont sous Linux se fait à l'aide de la commande brctl. Je vous renvoie au manuel (man brctl – Le manuel de brctl) pour les détails – mais j'ai mis quelques explications en commentaires ci-dessous.

Attention:

Configurer le pont nécessite de déconfiguer l'interface physique. Autrement dit, pendant quelques instants, l'hôte n'aura plus accès au réseau. Ca n'est pas grave si vous êtes connecté localement. C'est plus embêtant si vous êtes connecté à distance à l'hôte (par ssh, par exemple).

Un point à comprendre avant de commencer, c'est que dans ce montage, seul le pont lui-même aura une adresse IP. Pas les interfaces qui lui seront connectées. Il faut reconfigurer l'interface physique (eth1) et le tunnel (tap0) en conséquence:

sh# ifconfig eth1 0.0.0.0 promisc up
sh# ifconfig tap0 0.0.0.0 promisc up

Passons maintenant au pont à proprement parler. Après l'avoir créé, nous pouvons désactiver le Spanning Tree Protocol puisqu'il est certain qu'il n'y aura pas de boucle à ce niveau.

# création d'un nouveau pont nommé br0 
sh# brctl addbr br0
# notre pont n'utilise pas STP (Spanning Tree Protocol)
sh# brctl stp br0 off

Finalement, reste à connecter les interfaces au pont:

# connecte eth1 au pont
sh# brctl addif br0 eth1
# connecte tap0 au pont
sh# brctl addif br0 tap0

Depuis que nous avons déconfiguré l'interface physique, l'hôte n'a plus d'accès au réseau. Il est temps de le remettre en place. Ici, vous vous retrouverez en territoire connu avec les commandes ifconfig et route. La seule chose à remarquer, est que l'interface que l'on va configurer sera le pont – et pas l'interface physique:

# donne une adresse sur le réseau local au pont
sh# ifconfig br0 192.168.8.147 netmask 255.255.255.0
# fixe la passerelle par défaut
sh# route add default gw 192.168.8.254

Côté machine virtuelle

Les manipulations effectuées jusqu'à présent l'étaient sur l'hôte (la machine physique). Et devaient être effectuées sous l'identité root.

A partir de maintenant, nous allons passer sur la machine virtuelle. Celle-ci peut être lancée sous l'identité d'un utilisateur ordinaire:

sh$ linux ubda=lenny-image \
        con=pts  con0=fd:0,fd:1 \
        umid=uml \
        eth0=tuntap,tap0
[...]
uml login: 

Dans la commande ci-dessus, ce qui nous intéresse c'est le paramètre eth0=tuntap,tap0. Celui-ci ajoute à la machine virtuelle l'interface eth0 qui sera reliée au tunnel tap0 de l'hôte. Dans le monde réel, cela correspondrait à l'ajout d'une nouvelle carte réseau et au branchement d'un câble entre cette carte et le switch. Voyons ce que cela donne dans la machine virtuelle:

uml login: root
Password: 
uml:~# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 7a:a7:b6:a6:38:93  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:5 

Comme vous le constatez, l'interface est présente – mais reste à configurer. À partir de là, il n'y a plus rien de spécifique à UML: virtuelle ou pas, vous êtes en train de configurer une machine Linux. Un point c'est tout:

uml:~# ifconfig eth0 192.168.8.78 netmask 255.255.255.0 up

Piège:

N'oubliez pas que seuls les membres du groupe uml-net pourront se connecter au tunnel!

Dans le cas contraire, l'interface réseau eth0 n'apparaîtra pas – et vous obtiendrez l'erreur suivante en tentant de forcer son activation:

uml:~# ifconfig eth0 192.168.8.78 netmask 255.255.255.0 up
TUNSETIFF failed, errno = 1
SIOCSIFFLAGS: Operation not permitted
TUNSETIFF failed, errno = 1
SIOCSIFFLAGS: Operation not permitted

Nous pouvons facilement vérifier qu'à partir de maintenant, l'hôte est accessible – tout comme les autres machines situées sur le même sous-réseau:

uml:~# ping -c 1 192.168.8.147
PING 192.168.8.147 (192.168.8.147) 56(84) bytes of data.
64 bytes from 192.168.8.147: icmp_seq=1 ttl=64 time=13.9 ms

--- 192.168.8.147 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 13.943/13.943/13.943/0.000 ms
uml:~# ping -c 1 192.168.8.254
PING 192.168.8.254 (192.168.8.254) 56(84) bytes of data.
64 bytes from 192.168.8.254: icmp_seq=1 ttl=64 time=72.5 ms 

--- 192.168.8.254 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 72.579/72.579/72.579/0.000 ms

Quand à accéder à d'autres sous-réseaux, ce n'est qu'une histoire de passerelle à configurer:

uml:~# ping -c 1 192.168.1.2
connect: Network is unreachable
uml:~# route add default gw 192.168.8.254
uml:~# ping -c 1 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=63 time=0.456 ms

--- 192.168.1.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.456/0.456/0.456/0.000 ms

Enfin, pour l'accès au DNS, une modification de /etc/resolv.conf peut suffire:

uml:~# echo "nameserver 192.168.1.2" > /etc/resolv.conf 
uml:~# ping -c 1 www.google.com
PING www.l.google.com (209.85.229.147) 56(84) bytes of data.
64 bytes from ww-in-f147.1e100.net (209.85.229.147): icmp_seq=1 ttl=52 time=64.8 ms

--- www.l.google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 64.855/64.855/64.855/0.000 ms

Rendre les modifications permanentes

Nous avons vu qu'en quelques commandes, il était possible de configurer un hôte pour accepter la mise en réseau des machines virtuelles qu'il héberge.

Ca marche très bien. À ceci près que ces commandes doivent être exécutées par root et à chaque démarrage de la machine. Deux obstacles importants. Heureusement, il va être possible d'automatiser la mise en place du tunnel et du pont à chaque démarrage de l'hôte. De cette manière, toute l'infrastructure sera disponible – prête à accueillir les premières machines virtuelles invitées.

Pour l'automatisation, plusieurs options sont possibles. Sous Debian, on peut utiliser le fichier /etc/network/interfaces – qui est justement là pour ca!

Ouverture automatique du tunnel TUN/TAP

Pour créer automatiquement le tunnel TUN/TAP au démarrage du réseau, vous pouvez ajouter la strophe (stanza) suivante au fichier /etc/network/interfaces:

# VM TUN/TAP interfaces
auto tap0
iface tap0 inet manual
        pre-up tunctl -g uml-net -t tap0
        pre-up ifconfig tap0 up
        post-down tunctl -d tap0

Comme vous le voyez, je déclare une nouvelle interface nommée tap0 – et chargée automatiquement au démarrage. Cette interface n'a aucune configuration par défaut (mot-clé manual), et tout le travail d'activation (et de désactivation) est délégué aux utilitaires externes tunctl et ifconfig. Exactement comme nous l'avons fait manuellement plus haut.

Pont automatique

Installation

Sous Debian vous aurez besoin du paquet bridge-utils pour ce qui suit. Si ce logiciel n'est pas déjà sur votre machine utilisez le gestionnaire de paquets de votre distribution pour procéder à l'installation.

sh# apt-get install bridge-utils

L'activation du pont peut être réalisée de la même manière (avec pre-up et post-down). Mais, sous Debian, le paquet bridge-utils nous offre une manière plus confortable de procéder en ajoutant à interfaces(5) des options spécifiques:

# VM bridge interface
auto br0
iface br0 inet static
        address 10.129.36.99
        netmask 255.255.255.0
        network 10.129.36.0
        broadcast 10.129.36.255
        gateway 10.129.36.245
        bridge_stp off
        bridge_ports eth1 regex tap.* noregex

Piège:

Dans le fichier, le pont doit apparaître après les interfaces qui lui seront reliées!

Intuitivement, vous comprenez que bridge_stp off va être l'équivalent de la commande brctl stp br0 off utilisée précédemment. Quand à l'option bridge_port, elle permet de définir les interfaces qui seront reliées au pont.

Une petite astuce:

il est possible d'utiliser une expression rationnelle (entre regex et noregex) pour spécifier plusieurs ports à la fois. Ici, j'utilise cette possibilité pour bridger toutes les interfaces dont le nom correspond à l'expression rationnelle tap.*. D'accord, pour l'instant, je n'ai que tap0. Mais ça me simplifiera la vie quand je déciderai d'ajouter d'autres interfaces...

Si tout est en ordre, au prochain démarrage de la machine, toute votre infrastructure de réseau virtuelle sera mise en place – et prête à accueillir votre machine virtuelle UML. Comme nous ne voulons pas redémarrer notre machine tout de suite, il est aussi possible de redémarrer le réseau manuellement:

sh# /etc/init.d/networking restart
Reconfiguring network interfaces...
Set 'tap0' persistent and owned by gid 117

Waiting for br0 to get ready (MAXWAIT is 32 seconds).
done.

Sur la machine virtuelle

Pour rendre permanente la configuration de la machine virtuelle, pas de mystère: c'est une machine Linux comme une autre – et ici, sous Debian également. On peut configurer le réseau dans /etc/network/interfaces comme le montre l'exemple ci-dessous:

uml:~# cat /etc/network/interfaces
# Used by ifup(8) and ifdown(8). See the interfaces(5) manpage or
# /usr/share/doc/ifupdown/examples for more information.
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
	address 10.129.36.200
	netmask 255.255.255.0
	broadcast 10.129.36.255
	gateway 10.129.36.245

Un dernier mot

Une fois la configuration effectuée, les machines virtuelles peuvent être lancées par un utilisateur. Le seul compromis nécessaire – et qui est déjà fait par défaut sous Debian Lenny – c'est de rendre le fichier /dev/net/tun accessible en écriture aux utilisateurs du tunnel:

sh$ ls -l /dev/net/tun
0 crw-rw-rw- 1 root root 10, 200 2010-03-21 21:05 /dev/net/tun

Attention:

Autoriser l'écriture sur /dev/net/tun permet à vos utilisateurs de créer de nouveaux tunnels. Même si ceux-ci ne seront pas utilisables, cela constitue potentiellement un risque de déni de service par épuisement de ressources.

Enfin, sachez également qu'une même interface TUN/TAP ne peut être utilisée que par une seule machine à la fois. Par conséquent, si vous voulez faire tourner plusieurs machines virtuelles en parallèle, vous devrez créer d'autres tunnels tap1, tap2, etc.

Ressources