Pivert's Blog

3. Shorewall – Augmentez la réactivité avec la gestion de trafic


Reading Time: 13 minutes

Une gestion de trafic simple : traffic shaping et qualité de service (QoS)

Le QoS permet de réordonner les paquets dans la queue de sortie (buffer), pour donner la priorité au trafic tel que la navigation Web, l’ICMP ou le SSH.

Si votre upload est régulièrement encombré, et que vous utilisez des applications que demandent de l’interactivité (navigation web, SSH, jeux en ligne, téléphonie SIP, vidéoconférence…) vous ne pourrez plus vous en passer.
Gardez à l’esprit que le QoS de base ne s’applique qu’au trafic sortant, et s’applique idéalement sur Shorewall en tant que routeur internet.

Un exemple de ce que vous pouvez obtenir. La ligne est chargée à 100 % par une sauvegarde externalisée. À 14 h 30, un appel téléphonique rentre en SIP, et reçoit la classe de bande 1011 de priorité maximale.

Voici le troisième d’une série de 6 articles :

  1. Shorewall – Configuration de base en quelques minutes
  2. Shorewall – Routeur internet
  3. Shorewall – QoS & Traffic shaping pour améliorer les performances réseau
  4. Shorewall – Configurations avancées
  5. Shorewall – En entreprise : Haute disponibilité, sauvegarde & restauration
  6. Shorewall – En entreprise : Traçabilité, documentation des règles, revues d’audit, journalisation

Fonctionnement

Prenons l’exemple d’une ligne internet DSL, fibre ou câble surchargée. Les paquets IP sortants vont passer par une série de cartes réseau et routeurs. Chacun de ces éléments a des tampons (buffers) d’entrée et de sortie. Le plus important est d’identifier le tampon devant la ligne avec la plus petite bande passante, car c’est celui qui va se remplir et ralentir tout le trafic. Dans le cas d’une ligne internet surchargée, c’est le tampon de l’adaptateur internet (souvent appelé « modem ») qui se remplit. On a alors une sensation désagréable de lenteurs de connexion ou l’impossibilité d’avoir une conversation VOIP/vidéoconférence de qualité.

Pour que le QoS soit efficace il faut :

  1. Mise en forme du trafic (trafic shaping) : éviter à tout prix d’engorger le tampon de l’adaptateur internet (modem). Si l’adaptateur internet n’a pas de QoS / Traffic Shaping intégré, nous n’avons aucun contrôle sur ce tampon distant. Mais nous pouvons limiter le trafic en amont à un niveau légèrement inférieur à la capacité de la ligne, de manière que ce tampon reste toujours vide. Cela reviens à « ramener » le tampon saturé au niveau de notre serveur / routeur / station de travail.
  2. Ordonnancement : après avoir très légèrement réduit le débit de sortie, c’est maintenant le tampon local qui va se remplir. Et comme il est local, on peut y réordonner les paquets. Par exemple par ordre de priorité pour favoriser les paquets ayant besoin d’interactivité au détriment des paquets qui peuvent attendre.

Si le trafic est trop important, et si on a bien classé le trafique, il va s’empiler dans le tampon/la queue de moindre priorité. Toutes les 10 secondes, cette queue va être partiellement vidée (perturbée), et les paquets seront perdus. Ce n’est pas un problème, car la plupart des protocoles internet sont prévus pour gérer les engorgements et les pertes de paquets, en particulier TCP qui va demander à l’envoyeur de retransmettre et de diminuer son débit d’envoi.

Shorewall

Le QoS peut être très complexe. Mais Shorewall propose une implémentation « Simple » qui permet de couvrir la plupart des cas, et d’avoir un résultat satisfaisant rapidement. C’est ce mode que nous allons étudier et mettre en œuvre.

En mode TC Simple, Shorewall va créer 3 queues :

  • Classe de bande 1 : Trafic à envoyer en priorité
  • Classe de bande 2 : La bande par défaut (trafic non classé)
  • Classe de bande 3 : Trafic de moindre importance (qui peut être retardé)

La classification en « bande » 1 ou en « bande » 3 se fait dans l’ordre :

  • Avec des règles simples dans le fichier tcpri
  • Avec des règles avancées dans le fichier mangle
  • Avec un classement automatique d’après les flags TOS/DSCP du paquet
  • Si le paquet n’est toujours pas classé, il se retrouve en classe de bande 2
POSTROUTING
POSTROUTING
tcpri
(mangle)
tcpri…
Packet de haute priorité (petits paquets SSH, téléphonie SIP, videoconférence, requêtes DNS, ….) → Band 1
Packet de haute priorité (petits paquets SSH, téléphonie SIP, videoconférence, requêtes DNS, ….) → Band 1
Packet de basse priorité (Gros upload de fichiers, sauvegardes dans le cloud, ftp,…) → Band 3
Packet de basse priorité (Gros upload de fichiers, sauvegardes dans le cloud, ftp,…) → Band 3
Le reste du trafique, ou le trafique de moyenne priorité → Restent dans la Band 2 par défaut
Le reste du trafique, ou le trafique de moyenne priorité → Restent dans la Band 2 par défaut
1
1
1
1
3
3
3
3
3
3
2
2
2
2
3
3

Réseau

Réseau
Quand une queue SFQ est pleine, les paquets suivants sont abandonnés (tail-dropping).
Lorsque le trafic est réparti dans les 3 queues, la queue (101)3 a la plus forte probabilité de se remplir et ses paquets de se faire abandonner.
Quand une queue SFQ est pleine, les paquets s…
Classification et allocation de la bande 1,2 ou 3 par marquage des paquets
Classification et allocation de la…
Le Token Bucket Filter (TBF)
Limite la bande passante globale
Le Token Bucket Filter (TBF)…

Paquet IP

Paquet IP
CC BY-SA 4.0 – François Delpierre 2022
CC BY-SA 4.0 – François Delpierre 2022
sfq 1011
sfq 1011
sfq 1012
sfq 1012
sfq 1013
sfq 1013
Stochastic Fairness Queueing
Stochastic Fairness Queu…
La discipline Prio vide les queues de numéros inférieurs en priorité.
La discipline Prio vide les queues de numéros inférieurs en prio…
TBF
TBF
Prio
 discipline
Prio discipline
Implémentation du « Simple Trafic Control » de Shorewall
Implémentation du « Simple Trafic Control » de Shorewall
Text is not SVG – cannot display

En pratique

Il est préférable de mettre en place une configuration de qualité de service et de mise en forme de trafic le plus près possible du goulot d’étranglement, idéalement juste derrière votre modem ou internet adapter. Pour faire simple, et comme nous ne verrons les configurations avancées que dans le prochain chapitre, nous allons continuer dans la VM utilisée dans le premier chapitre.

Certains modems – routeurs intègrent des fonctions de base de qualité de service, mais en général très (trop) limités. Vérifiez et désactivez-la si vous implémentez cette solution.

Copiez les fichiers de templates

sudo cp /usr/share/shorewall/configfiles/tcinterfaces.annotated /etc/shorewall/tcinterfaces
sudo cp /usr/share/shorewall/configfiles/tcpri.annotated /etc/shorewall/tcpri
sudo cp /usr/share/shorewall/configfiles/mangle.annotated /etc/shorewall/mangle

Mettre le paramètre TC_ENABLED à «Simple» dans /etc/shorewall/shorewall.conf. Vous devriez avoir ceci :

sudo grep ^TC_ /etc/shorewall/shorewall.conf
TC_ENABLED=Simple
TC_EXPERT=No
TC_PRIOMAP="2 3 3 3 2 3 1 1 2 2 2 2 2 2 2 2"
TC_BITS=

Le QoS va s’appliquer en priorité aux règles dans le fichier tcpri et éventuellement mangle (configuration avancée). Si aucune correspondance n’est trouvée, la priorité va être définie en fonction du type de service (ToS) du paquet IP en fonction de la TC_PRIOMAP. (Laisser la priomap par défaut)

Déterminez votre interface de sortie

ip route show default
default via 192.168.130.1 dev internet proto static

Ici, c’est l’interface « internet »

Déterminez l’upload maximum de la ligne

Lorsque la ligne est libre (pas de gros upload encours), utilisez un service tel que https://www.speedtest.net/ pour mesurer le débit disponible.

Attention, seul l’upload nous intéresse ici. Dans l’exemple, Speedtest me donne upload de 8.99 Mbps. Pour pouvoir utiliser des nombres entier, on va convertir cette valeur en « Kilobits per second » en multipliant par 1024.

# echo "8.99*1024" | bc
9205.76

Nous allons prendre une valeur légèrement inférieure, ici nous allons commencer avec 9200kbit.

Définir l’interface dans tcinterfaces

Maintenant qu’on a la bande passante maximale en upload (9200kbit) et le nom de l’interface (internet), on peut définir l’interface de sortie dans le fichier
/etc/shorewall/tcinterfaces

#INTERFACE      TYPE            IN_BANDWIDTH            OUT_BANDWIDTH
internet        external        0                       9200kbit

On met l’interface en « external » puisque c’est celle qui va vers internet. Et 0 dans le IN_BANDWIDTH car on ne veut pas limiter le débit en entrée.

Remarque : Vous pourriez limiter la bande passante entrante de la même manière, mais ça n’aura que peu d’effet : les paquets seront abandonnés sur votre firewall local au lieu du routeur distant de l’ISP (Internet Service Provider).

On peut maintenant redémarrer Shorewall: shorewall restart

Vérification

root@pivert-VirtualBox:/etc/shorewall# tc qdisc
qdisc noqueue 0: dev lo root refcnt 2 
qdisc tbf 1: dev enp0s3 root refcnt 2 rate 9200Kbit burst 10Kb lat 200ms 
qdisc sfq 1011: dev enp0s3 parent 101:1 limit 127p quantum 1875b depth 127 divisor 1024 perturb 10sec 
qdisc sfq 1013: dev enp0s3 parent 101:3 limit 127p quantum 1875b depth 127 divisor 1024 perturb 10sec 
qdisc prio 101: dev enp0s3 parent 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc sfq 1012: dev enp0s3 parent 101:2 limit 127p quantum 1875b depth 127 divisor 1024 perturb 10sec 

Explications

Shorewall met en place un algorithme de «Simple» «Traffic Classification»

On retrouve :

  • le « Tocken Bucket Filter » qui va limiter la bande passante en sortie à 9200kbits
  • la discipline prio va toujours privilégier la/les bandes inférieures (1, puis 2 au détriment de la bande 3, qui correspondent aux sfq 1011, 1012 et 1013)
  • La priomap par défaut, qui va classer le trafique en fonction du ToS des paquets sortants, si le ToS a été défini. (C’est rarement le cas). Remarquez que les bandes sont numérotées à partir de 0 dans la priomap : les bandes 0,1,2 correspondent aux sfq 1,2,3.
  • Les 3 « Stochastic Fairness Queueing » (sfq) pour définir une queue pour chacune des 3 bandes.

Remarque : Shorewall nomme les bandes 1,2 et 3, alors que dans la documentation de tc-prio et dans la priomap elles sont nommées 0,1 et 2. Voici la définition de l’algorithme

       When dequeueing, band 0 is tried first and only if it did not
       deliver a packet does PRIO try band 1, and so onwards. Maximum
       reliability packets should therefore go to band 0, minimum delay
       to band 1 and the rest to band 2.

Classification du trafic

Il s’agit probablement de la phase la plus critique. Il y a plusieurs possibilités :

  • On peut matcher le trafic à partir de règles dans le fichier tcpri
  • On peut matcher le trafic à partir de règles dans le fichier mangle qui offre beaucoup plus de possibilités
  • Certaines applications permettent de définir le ToS ou le DSCP. Par exemple pour rclone:
    rclone --dscp CS1 ...

Étude d’un cas de classification du trafic

Je vais prendre le cas d’une tâche de sauvegarde rclone sur un serveur web (192.168.66.10) qui sature la connexion internet. C’est un cas intéressant, car on va pouvoir utiliser les 4 options décrites ci-dessus.

1. Utilisation du tcpri
#BAND   PROTO   PORT    ADDRESS         INTERFACE       HELPER
1       TCP     853     -               -               -       # DNS-over-TLS (stubby)
1       -       -       -               -               sip
3       -       -       192.168.66.10   -               -       # ALL Traffic from Web Server in Band3

Dans le tcpri, on peut matcher :

  • Le protocole et le port (source et destination), la première ligne passe en priorité (bande 1) le traffic DNS (DoT)
  • Le “helper” iptables, dans ce cas sip. Pour donner la priorité à ce trafic. Vous pouvez lister les conntrack helpers avec la commande
    ls -l /usr/src/linux-headers-$(uname -r)/include/linux/netfilter/
  • La sélection sur l’IP source du serveur Web pour que les backups passent en bande 3.

Inconvénients de cette solution : tous les paquets en provenance du serveur web vont passer en bande 3 (basse priorité), y compris le trafic de clients externes navigants sur le site web.

2. Utilisation tu fichier mangle

Ce fichier permet des configurations beaucoup plus avancées que tcpri, et peut être utilisé avec le TC_ENABLED shorewall en mode “Simple”. On peut utiliser le fichier mangle en plus du fichier tcpri si il est bien activé dans la configuration de Shorewall.

Vérifier que MANGLE_ENABLED est à Yes (par défaut) :

root@burns2:/etc/shorewall# grep MANGLE shorewall.conf
MANGLE_ENABLED=Yes

Voici un exemple de configuration pour un serveur web

##############################################################################################################################################################
#ACTION                 SOURCE                          DEST            PROTO   DPORT   SPORT   USER    TEST    LENGTH  TOS     CONNBYTES       HELPER  PROBA   DSCP    SWITCH
MARK(1):T               192.168.66.11                   -               tcp     -       443     -       -       -       -       -               -       -       -       -       # browing traffic from Web Servers
MARK(3):T               192.168.66.11                   -               tcp     443     -       -       -       -       -       -               -       -       -       -       # backup traffic from Web Servers

Le fichier mangle étant plus souple, on peut:

  • Isoler le trafic sortant, à direction du port 443, et donc le trafic de sauvegarde →Class 3
  • Isoler le trafic sortant, à partir du port 443, et donc le trafic de navigation sur le site → Class 1

Avec le fichier mangle, on peut aller beaucoup plus loin. Exemple plus avancé, recommandé pour commencer, et utilisé pour les tests suivants :

#ACTION                 SOURCE                          DEST            PROTO   DPORT   SPORT   USER    TEST    LENGTH  TOS     CONNBYTES       HELPER  PROBA   DSCP    SWITCH
MARK(1):T               192.168.0.0/16                  -               -       -       -       -       -       0:150   -       -               -       -       -       -       # very small traffic
MARK(3):T               192.168.0.0/16                  -               tcp     443     -       -       -       -       -       750::O:A        -       -       -       -       # Paquets sortants d'une connexion https sortante dont la moyenne de la taille des packets est supérieure à 750bits, à mettre en bande de classe 3 (basse priorité)
  • La première règle définit que tous les paquets de petite taille (<99 octets) sont prioritaires (→ Classe 1)
    Cette règle est particulièrement efficace sur les appels de type VOIP, car les paquets sont souvent UDP de petite taille (128 octets)
  • La seconde règle définit que tous les paquets qui matchent les conditions suivantes sont en classe 3:
    • La connexion provient du réseau interne (Source 192.168.0.0/16, et utilisation du CONNBYTES)
    • La moyenne (:A pour average) de la taille des paquets sortants (:O pour original destination) est supérieure à 500 bytes (500:)

Si vous n’êtes pas certain des règles à utiliser, je vous recommande de laisser le fichier tcpri vide, et de commencer avec la paire de règles ci-dessus dans le fichier mangle.

Grâce aux actions CONNBYTES et aux commandes SAVE et RESTORE, il est possible de matcher sur les connexions, et non plus uniquement les paquets.
Gardez en tête que le QoS ne se fera que sur le marquage du paquet, et non de la connexion. Si la connexion est marquée, on peut “redescendre” le marquage sur le paquet avec l’action RESTORE.

3. Utilisation du ToS/DSCP

Si vous utilisez une application qui permet de définir directement le ToS ou le DSCP, il est plus facile de matcher son traffic. C’est l’idéal.

Pour rclone par exemple, il faut juste lui ajouter l’option –dscp, suivit de la classe. J’ai choisi la classe de service 1 (avec une moindre priorité), donc rclone est lancé avec l’option –dscp CS1. Et le trafic de sauvegarde sera automatiquement en classe 3.

  • Explications sur le DSCP (anglais)
  • Shorewall ne supporte pas toutes les classes DSCP, vérifiez dans les annotations du fichier mangle si vous êtes parti du fichier
    /usr/share/shorewall/configfiles/mangle.annotated
    ou man shorewall-mangle
4. Tests

Pour pouvoir tester la solution, il faut saturer l’upload avec un trafic que vous avez classé en bande 3. Puis utilisez la commande tc -s (pour statistics). Pour les tests, je lancer une grosse sauvegarde sur un service S3. Voici le monitoring du modem.

P.S. Lorsque vous adaptez les règles de classification, un shorewall reload suffit. Un shorewall reload ou restart va mettre à zéro les compteurs de statistiques.

Voici ce que ça donne avec les 2 règles dans le fichier mangle (règles recommandées ci-dessus).

Après quelques heures de saturation de l’upload avec une sauvegarde informatique, donc avec des paquets sortant vers le port 443 et dont la taille moyenne dépasse les 750 octets (deuxième règle du fichier mangle), on peut constater que les filtres fonctionnent :

  • Les paquets sont bien droppés dans la bande 3 (la sfq 1013), et aucun dans les bandes 1012 et 1011 de plus haute priorité.
  • On voit que l’upload est toujours en cours, car le backlog de la sfq 1013 se remplit régulièrement. (Il est à 95 paquets dans l’exemple). Les sfq sont limitées à 128 paquets (limit 127p). Les backlogs des sfq de plus hautes priorités sont vides.
  • On voit également que le nombre de paquets droppés par le tbf est identique aux paquets droppés de la bande 3, puisqu’aucun paquet n’a été droppé dans les autres bandes.
  • On peut également voir le volume important qui est passé dans la sfq 1013 depuis le dernier shorewall reload : 15022223566 octets
    Pour l’avoir en Go :
root@burns2:/etc/shorewall# bc -l <<< "scale=3;15022223566/2^30"
13.990

J’en ai profité pour relancer un Speedtest, qui mondre un débit quasiment identique, malgré la saturation de la ligne:

Le cas de speedtest est un peu biaisé ici, car il a utilisé le port de destination 8080, et donc même si les paquets étaient volumineux, ce trafic s’est retrouvé d’office dans la bande 2 par défaut.

5. Problèmes courants
  • Bien que vous saturiez la ligne en upload, tc -s qdisc ne montre aucun paquet abandonné (dropped). Cela signifie que la mise en forme du trafic ne se fait pas car vous avez choisi un débit de sortie plus élevé que ce que la ligne ne peut transporter. Les paquets sont donc abandonnés sur le modem, et non pas sur le Shorewall. Réduisez le OUT_BANDWIDTH de l’interface de sortie dans le fichier tcinterfaces.
  • Des paquets sont bien abandonnés, mais pas dans la bonne classe de bande. Vérifiez ou simplifiez les règles dans tcpri et dans mangle et testez.

Monitoring avancé

On peut relancer la commande tc -s qdisc show dev internet de multiple fois, idéalement après un shorewall reload qui met à zéro les compteurs. Ou bien laisser tourner dans une console :

watch tc -s qdisc

La commande tc a également une sortie en JSON qui la rend facile à exploiter à partir de scripts ou à partir de jq

jq ( apt install jq pour l’installer )
~# tc -s -j qdisc | jq -r '.[] | select( .kind == "sfq") | { Bande: ( .handle | match("[0-9]+([0-9]):") .captures[0] .string |tonumber ) , Megaoctets: (.bytes/pow(2;20) |round), Paquets: .packets, Abandons: .drops, Longueur_queue: .qlen}' | jq -s 'sort_by(.Bande)'
[
  {
    "Bande": 1,
    "Megaoctets": 187,
    "Paquets": 2423130,
    "Abandons": 0,
    "Longueur_queue": 0
  },
  {
    "Bande": 2,
    "Megaoctets": 624,
    "Paquets": 974656,
    "Abandons": 5754,
    "Longueur_queue": 0
  },
  {
    "Bande": 3,
    "Megaoctets": 41295,
    "Paquets": 28714328,
    "Abandons": 25966,
    "Longueur_queue": 94
  }
]
Exporter en Python

Voici un mini exporter Prometheus en Python pour cette commande. Il dépend du package python3-prometheus-client.

#!/usr/bin/env python
# cSpell:includeRegExp /".*",/
# cSpell:includeRegExp /\(f?".*"/
# 
# Prometheus exporter for SFQ qdisc queues
#
# You should adapt the name of the inerface, and maybe queues match and listening port.
# Install the python library
# apt install python3-prometheus-client
# Tested on Shorewall Simple TC / Ubuntu 22.04 / Python 3.10
# 
# François Delpierre 2022
# GNU General Public License
#

from __future__ import annotations
import time
from prometheus_client.core import GaugeMetricFamily, CounterMetricFamily, REGISTRY
from prometheus_client import start_http_server
import subprocess
import shlex
import json


INTERFACE="internet"
COMMAND=f"tc -s -j qdisc show dev {INTERFACE}"

COUNTERS = ['bytes', 'drops', 'overlimits', 'packets', ]
GAUGES = ['backlog', 'qlen' ]


def execute(cmd) -> tuple:                                                                                              
    output = subprocess.Popen(shlex.split(cmd),                                                                         
            stdout=subprocess.PIPE,                                                                                     
            stderr=subprocess.STDOUT)                                                                                   
    return output.communicate() 


class CustomCollector(object):
    def __init__(self) -> None:
        pass

    def collect(self):
        stdout = execute(COMMAND)[0]

        for k in COUNTERS:
            counter = CounterMetricFamily(f'trafic_control_{k}', f'Trafic Control {k}', labels=['interface', 'handle', 'kind'])
            for tc in json.loads(stdout):
                counter.add_metric(['internet', tc['handle'], tc['kind']], tc[k])
            yield counter

        for k in GAUGES:
            gauge = GaugeMetricFamily(f'trafic_control_{k}', f'Trafic Control {k}', labels=['interface', 'handle', 'kind'])
            for tc in json.loads(stdout):
                gauge.add_metric(['internet', tc['handle'], tc['kind']], tc[k])
            yield gauge

if __name__ == '__main__':
    start_http_server(9102)
    REGISTRY.register(CustomCollector())
    while True:
        time.sleep(1)

C’est rudimentaire, et une fois Prometheus et Grafana configurés, ça donne ceci.

Grafana / qdisc

On peut y retrouve la pointe du Speedtest réalisé précédemment (j’avais configuré ce script avant), et on remarque :

  • La bande 2 (1012) reçoit toute la bande passante disponible au détriment de la bande 3 (1013).
  • Les paquets sont habituellement abandonnés en bande 3, mais au moment du Speedtest, c’est dans la bande 2 que les paquets ont le plus été abandonnés.
  • Seule la SFQ 1013 se remplit, sauf au moment du Speedtest où on voit la SFQ 1012 de la bande 2 se remplir.

Après 36 h, 145 Go transférés sur une ligne internet limitée à 9200 kbps d’upload et plus aucun impact sur la navigation, la téléphonie, les video-conférence ou les jeux en ligne.

Grafana qdisc sfq monitoring
Synology Hyper Backup after 36h

Conclusions

Le trafic control en mode « Simple » de Shorewall, n’est pas bien compliqué, et il permet déjà de couvrir tous les problèmes classiques de saturation d’upload internet. L’article parait long, mais c’est tellement plus simple quand on comprend ce qu’on fait ! J’espère que cet article vous aidera à tirer le meilleur parti de cette option intéressante de Shorewall.

References

Like it ?

Get notified on new posts (max 1 / month)
Soyez informés lors des prochains articles

Leave a Reply

Your email address will not be published. Required fields are marked *