[HowTo] Simuler un WAN avec un Raspberry

J’ai récemment eu besoin de simuler une liaison WAN dégradée afin de tester la réaction de boitiers SD-WAN et plus particulièrement leurs mécanismes d’optimisation TCP/UDP. J’avais pour habitude d’utiliser la distribution linux « WANem » qui a été créée il y a longtemps par des consultants de chez TATA. Le souci de WANem c’est que pour cet exercice, il faut le mettre sur une clé USB, le lancer sur un mini-PC avec plusieurs cartes réseaux ou son propre PC, c’est embêtant et peu pratique à transporter chez les clients. Ayant un Raspberry Pi 3 à disposition avec un module USB/Ethernet, je me suis lancé dans le montage d’un outil plus pratique que l’habituel WANem.

L’objectif était de créer un bridge afin de faire fonctionner le Raspberry PI comme un simple « câble » mais également d’agir sur le comportement des paquets qui entrent et sortent grâce à Netem. L’utilisation du bridge évite de devoir configurer des IP statiques, du NAT et un DHCP.

Dans mon cas, j’ai placé le Raspberry derrière un routeur afin d’ajouter de la latence et dropper des paquets de façon prédictible et donc réduire la qualité du lien WAN à disposition. Mais le Raspberry pourrait très bien être placé entre deux PC ou derrière un Switch.

Ci-dessous le schéma de montage:
raspberry

Voici donc la marche à suivre, en mode quick & dirty :)
Note: Je ne suis pas un expert linux donc il y à peut-être encore plus simple à faire, mais les lignes qui suivent ont le mérite de vous guider simplement dans la réalisation de cet outil.

Configuration initiale du Raspberry

Le test a été réalisé avec un Raspberry Pi 3 Official Desktop Starter Kit (16GB, White) et un UGREEN Réseau Adaptateur USB 3.0 vers RJ45 Gigabit Ethernet USB Réseau que vous pouvez vous procurer facilement chez Amazon. L’adaptateur a été reconnu directement en ‘Eth1′ sans rien faire, et ça c’est cool !

Après le déballage du boitier en mode usine, puis installation de Raspbian light, mise à jour du système:

# apt-get update
# apt-get upgrade

Configuration du Bridge

Afin de monter le pont (bridge) et transformer le Raspberry en Switch, on installe le package bridge-utils:

# apt-get install bridge-utils

On crée le pont br0:

# brctl addbr br0
Add bridge failed: package not installed

Et là, pour ma part, ce fut le premier problème rencontré, l’option « 802.1d Ethernet Bridging » n’est pas activée par défaut dans le noyau précompilé du Raspberry. Il est donc nécessaire de le recompiler avec cette fonctionnalité. Voici donc comment je me suis lancé dans une recompilation de noyau au bout de 2 minutes… une première pour moi donc après avoir fait le tour de google, j’en suis arrivé aux étapes suivantes.

Installer les packages nécessaires pour la compilation:

# apt-get install bzip2 libncurses5-dev fakeroot kernel-package

Se procurer les sources du noyau, en fonction de celui installé.
De mon côté, un « uname -r »  m’as permis de trouver la version 4.9.41, puis une recherche sur Google m’as mené vers le site https://www.spinics.net/lists/announce-kernel/msg01939.html où j’ai trouvé les sources nécessaires.

Voici comment les récupérer:

# mkdir ~/kernel/
# wget -P ~/kernel https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.9.41.tar.xz">https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.9.41.tar.xz

On a maintenant un fichier contenant les sources du noyau Linux dans le répertoire ~/kernel. Nous allons réaliser un paquet Debian pour la création du noyau.

# cd ~/kernel 
# tar xvjf linux-4.9.41.tar.xz
# ln -sfn linux-4.9.41 linux
# cd linux/

Il faut ensuite trouver le fichier de configuration modèle, stocké dans un fichier .config à la racine des sources du noyau.  Ce fichier est lu et modifié par l’utilitaire de configuration du noyau, et il est ensuite lu lors de la compilation du noyau.  J’ai trouvé le miens ici :

# cp /boot/config.txt ~/kernel/linux/
# cd ~/kernel/linux/
# cp config.txt .config

Il ne reste qu’à lancer l’utilitaire de configuration du noyau, tapez en mode utilisateur:

# make menuconfig

Vous arrivez alors dans l’interface de configuration du noyau :
Pour notre besoin, il faut aller dans Device Drivers > Networking > Support > Networking Options et cocher « Mgt –  802.1d Ethernet Bridging ».

Une fois coché, on peut recompiler le noyau et configurer notre bridge via le package bridge-utils.

Configuration du bridge « temporaire »

Installer le programme de gestion des ponts réseau :

# apt-get install bridge-utils

Solution temporaire:

Création du bridge br0:

# sudo brctl addbr br0

Ajout des interfaces Eth0 et Eth1 dans le bridge:

# brctl addif br0 eth0
# brctl addif br0 eth1

Activation du bridge:

# sudo ifconfig br0 up

Vérification de la configuration:

# sudo brctl show br0
# sudo brctl showmacs br0

Pour supprimer la configuration:

# sudo ifconfig br0 down
# sudo brctl delbr br0

Solution persistante au redémarrage

Pour créer une solution pérenne dans le temps, si vous voulez dédier votre raspberry aux tests WAN :p il est possible de configurer le bridge en dur dans le fichier /etc/network/interfaces.

Backup du fichier existant:

# cp /etc/network/interfaces /etc/network/interfaces.old
# nano /etc/network/interfaces
 
auto br0
iface br0 inet dhcp
bridge_ports eth0 eth1

On relance la configuration des interfaces réseau:

# /etc/init.d/networking restart

Simulation du WAN

Nous allons créer des problèmes similaires à ce que l’on peut trouver sur un WAN mais sur l’interface Eth0 du Raspberry (Outbound) grâce au module Netem (https://wiki.linuxfoundation.org/networking/netem) de linux et à sa commande « tc », nous avons la possibilité d’ajouter de la latence, perdre des paquets, les dupliquer, les réordonner..etc.

Avant de commencer les tests, ping depuis le PC vers Internet:

C:\Users\bgo>ping 8.8.8.8 -t
Envoi d’une requête 'Ping'  8.8.8.8 avec 32 octets de données :
Réponse de 8.8.8.8 : octets=32 temps=72 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=49 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=71 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=78 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=50 ms TTL=55

Delay

sudo tc qdisc add dev eth0 root netem delay 100ms
C:\Users\bgo>ping 8.8.8.8 -t
Envoi d’une requête 'Ping'  8.8.8.8 avec 32 octets de données :
Réponse de 8.8.8.8 : octets=32 temps=20 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=21 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=20 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=21 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=120 ms TTL=55 # Début du delay
Réponse de 8.8.8.8 : octets=32 temps=121 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=120 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=121 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=121 ms TTL=55 # Fin du delay
Réponse de 8.8.8.8 : octets=32 temps=21 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=22 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=20 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=20 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=20 ms TTL=55

Packet Loss

sudo tc qdisc add dev eth0 root netem loss 15%
Réponse de 8.8.8.8 : octets=32 temps=21 ms TTL=55
Délai d’attente de la demande dépassé.
Délai d’attente de la demande dépassé.
Réponse de 8.8.8.8 : octets=32 temps=25 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=20 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=20 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=19 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=35 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=20 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=20 ms TTL=55
Délai d’attente de la demande dépassé.
Réponse de 8.8.8.8 : octets=32 temps=31 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=26 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=20 ms TTL=55
Réponse de 8.8.8.8 : octets=32 temps=51 ms TTL=55

Packet duplication

sudo tc qdisc add dev eth0 root netem duplicate 1%

Packet corruption

sudo tc qdisc add dev eth0 root netem corrupt 0.1%

Packet re-ordering

sudo tc qdisc add dev eth0 root netem gap 5 delay 10ms

Annulation / Remise à zéro
Pour annuler n’importe laquelle des actions, taper la commande suivante:

sudo tc qdisc del dev eth0 root

Si vous voulez vraiment vous faire du mal, il est possible de configurer tous ces paramètres en même temps, comme par exemple ajouter 100ms de delay, perdre 15% de paquets et dupliquer 1% de ceux-ci:

sudo tc qdisc add dev eth0 root netem delay 100ms loss 15% duplicate 1%

Pour arrêter:

sudo tc qdisc del dev eth0 root

Simulation WAN dès le démarrage du Raspberry

Pour automatiser un ou plusieurs de ces paramètres au démarrage du Raspberry PI afin qu’il fasse partie intégrante de votre toolbox d’ingénieur réseau, sans avoir besoin d’un écran/clavier en arrivant sur le site à tester:

On crée le fichier de script

touch /etc/init.d/packetloss

On édite le fichier de script:

nano /etc/init.d/packetloss

On ajoute les lignes suivantes, à modifier en fonction de vos besoins:

touch /var/lock/packetloss
case "$1" in
   start)
      echo "Loss of 15% initiated…"
      sudo tc qdisc add dev eth0 root netem loss 15%
   stop)
      echo "Loss of 15% removed…"
      sudo tc qdisc del dev eth0 root 
   *)
      echo "usage: /etc/init.d/packetloss {start|stop}"
      exit 1
   ;;
esac
exit 0

Ajouter dans /etc/rc.local la commande:

sudo /etc/init.d/packetloss start

Redémarrer et constater les pertes de paquets dès que l’OS sera prêt :)
Cette solution permet de sortir le Raspberry, le mettre en coupure, le démarrer et le rendre opérationnel immédiatement sans avoir besoin de sortir l’écran/clavier ou le configurer en SSH.

Sources utilisées pour ce test et l’article:
https://linux.developpez.com/formation_debian/bridge.html
https://linux.developpez.com/formation_debian/config-noyau.html#AEN3362
https://www.spinics.net/lists/announce-kernel/msg01939.html
https://formation-debian.viarezo.fr/bridge.html
https://blog.sleeplessbeastie.eu/2012/12/24/debian-how-to-transparently-bridge-ethernet-interfaces/
https://wiki.linuxfoundation.org/networking/netem

Benoit

Network engineer CCIE #47705, focused on R&S, Data Center and SDN.

More Posts - Website

Follow Me:
TwitterLinkedIn

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>