Utilisation de TSDuck pour surveiller les flux IP (TS)

Aujourd'hui, il existe des solutions (propriétaires) prêtes à l'emploi pour surveiller les flux IP (TS), par exemple VB и iQ, ils ont un ensemble de fonctions assez riche et généralement les grands opérateurs traitant des services de télévision disposent de telles solutions. Cet article décrit une solution basée sur un projet open source TSDuck, conçu pour un contrôle minimal des flux IP (TS) par le compteur CC (compteur de continuité) et le débit binaire. Une application possible est de contrôler la perte de paquets ou l'ensemble du flux via un canal L2 loué (qui ne peut pas être surveillé normalement, par exemple en lisant les compteurs de perte dans les files d'attente).

Très brièvement sur TSDuck

TSDuck est un logiciel open source (licence BSD à 2 clauses) (un ensemble d'utilitaires de console et une bibliothèque pour développer des utilitaires ou des plugins personnalisés) pour manipuler les flux TS. En entrée, il peut fonctionner avec IP (multicast/unicast), http, hls, tuners dvb, démodulateur dektec dvb-asi, il y a un générateur de flux TS interne et la lecture de fichiers. La sortie peut être l'écriture dans un fichier, IP (multicast/unicast), hls, modulateurs dektec dvb-asi et HiDes, lecteurs (mplayer, vlc, xine) et drop. Divers processeurs de trafic peuvent être inclus entre l'entrée et la sortie, par exemple, le remappage PID, le brouillage/désembrouillage, l'analyse du compteur CC, le calcul du débit binaire et d'autres opérations typiques pour les flux TS.

Dans cet article, les flux IP (multicast) seront utilisés comme entrée, les processeurs bitrate_monitor (d'après le nom, il est clair de quoi il s'agit) et la continuité (analyse des compteurs CC) sont utilisés. Vous pouvez facilement remplacer la multidiffusion IP par un autre type d'entrée pris en charge par TSDuck.

Il existe versions/paquets officiels TSDuck pour la plupart des systèmes d'exploitation actuels. Ils ne sont pas disponibles pour Debian, mais nous avons réussi à les compiler sous debian 8 et debian 10 sans aucun problème.

Ensuite, la version TSDuck 3.19-1520 est utilisée, Linux est utilisé comme système d'exploitation (debian 10 a été utilisé pour préparer la solution, CentOS 7 a été utilisé pour une utilisation réelle)

Préparation de TSDuck et du système d'exploitation

Avant de surveiller les flux réels, vous devez vous assurer que TSDuck fonctionne correctement et qu'il n'y a pas de baisse au niveau de la carte réseau ou du système d'exploitation (socket). Ceci est nécessaire pour ne pas deviner plus tard où les chutes se sont produites - sur le réseau ou «à l'intérieur du serveur». Vous pouvez vérifier les baisses au niveau de la carte réseau avec la commande ethtool -S ethX, le réglage est effectué par le même ethtool (généralement, vous devez augmenter le tampon RX (-G) et parfois désactiver certains déchargements (-K)). En règle générale, il peut être conseillé d'utiliser un port séparé pour recevoir le trafic analysé, si possible, cela minimise les faux positifs associés au fait que la chute s'est produite exactement sur le port de l'analyseur en raison de la présence d'un autre trafic. Si cela n'est pas possible (un mini-ordinateur/NUC avec un port est utilisé), alors il est fortement souhaitable de mettre en place la priorisation du trafic analysé par rapport au reste sur l'appareil auquel l'analyseur est connecté. En ce qui concerne les environnements virtuels, ici, vous devez être prudent et être capable de trouver des pertes de paquets à partir d'un port physique et se terminant par une application à l'intérieur d'une machine virtuelle.

Génération et réception d'un flux à l'intérieur de l'hôte

Comme première étape dans la préparation de TSDuck, nous allons générer et recevoir du trafic au sein d'un seul hôte en utilisant netns.

Préparation de l'environnement :

ip netns add P #создаём netns P, в нём будет происходить анализ трафика
ip link add type veth #создаём veth-пару - veth0 оставляем в netns по умолчанию (в этот интерфейс будет генерироваться трафик)
ip link set dev veth1 netns P #veth1 - помещаем в netns P (на этом интерфейсе будет приём трафика)
ip netns exec P ifconfig veth1 192.0.2.1/30 up #поднимаем IP на veth1, не имеет значения какой именно
ip netns exec P ip ro add default via 192.0.2.2 #настраиваем маршрут по умолчанию внутри nents P
sysctl net.ipv6.conf.veth0.disable_ipv6=1 #отключаем IPv6 на veth0 - это делается для того, чтобы в счётчик TX не попадал посторонний мусор
ifconfig veth0 up #поднимаем интерфейс veth0
ip route add 239.0.0.1 dev veth0 #создаём маршрут, чтобы ОС направляла трафик к 239.0.0.1 в сторону veth0

L'environnement est prêt. Nous démarrons l'analyseur de trafic :

ip netns exec P tsp --realtime -t 
 -I ip 239.0.0.1:1234 
 -P continuity 
 -P bitrate_monitor -p 1 -t 1 
 -O drop

où "-p 1 -t 1" signifie que vous devez calculer le débit toutes les secondes et afficher des informations sur le débit toutes les secondes
Nous démarrons le générateur de trafic avec une vitesse de 10Mbps :

tsp -I craft 
 -P regulate -b 10000000 
 -O ip -p 7 -e --local-port 6000 239.0.0.1:1234

où "-p 7 -e" signifie que vous devez emballer 7 paquets TS dans 1 paquet IP et le faire dur (-e), c'est-à-dire attendez toujours 7 paquets TS du dernier processeur avant d'envoyer un paquet IP.

L'analyseur commence à produire les messages attendus :

* 2020/01/03 14:55:44 - bitrate_monitor: 2020/01/03 14:55:44, TS bitrate: 9,970,016 bits/s
* 2020/01/03 14:55:45 - bitrate_monitor: 2020/01/03 14:55:45, TS bitrate: 10,022,656 bits/s
* 2020/01/03 14:55:46 - bitrate_monitor: 2020/01/03 14:55:46, TS bitrate: 9,980,544 bits/s

Ajoutez maintenant quelques gouttes :

ip netns exec P iptables -I INPUT -d 239.0.0.1 -m statistic --mode random --probability 0.001 -j DROP

et des messages comme celui-ci apparaissent :

* 2020/01/03 14:57:11 - continuity: packet index: 80,745, PID: 0x0000, missing 7 packets
* 2020/01/03 14:57:11 - continuity: packet index: 83,342, PID: 0x0000, missing 7 packets 

qui est attendu. Désactivez la perte de paquets (ip netns exec P iptables -F) et essayez d'augmenter le débit du générateur à 100 Mbps. L'analyseur signale un tas d'erreurs CC et environ 75 Mbps au lieu de 100. Nous essayons de déterminer qui est à blâmer - le générateur n'a pas le temps ou le problème n'est pas dedans, pour cela nous commençons à générer un nombre fixe de paquets (700000 100000 paquets TS = XNUMX XNUMX paquets IP) :

# ifconfig veth0 | grep TX
       TX packets 151825460  bytes 205725459268 (191.5 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
# tsp -I craft -c 700000 -P regulate -b 100000000 -P count -O ip -p 7 -e --local-port 6000 239.0.0.1:1234
* count: PID    0 (0x0000):    700,000 packets
# ifconfig veth0 | grep TX
        TX packets 151925460  bytes 205861259268 (191.7 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Comme vous pouvez le voir, exactement 100000 151925460 paquets IP ont été générés (151825460-1). Voyons donc ce qu'il se passe avec l'analyseur, pour cela on vérifie avec le compteur RX sur veth0, il est strictement égal au compteur TX sur vethXNUMX, puis on regarde ce qui se passe au niveau socket :

# ip netns exec P cat /proc/net/udp                                                                                                           
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops             
  133: 010000EF:04D2 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 72338 2 00000000e0a441df 24355 

Ici, vous pouvez voir le nombre de baisses = 24355. Dans les paquets TS, c'est 170485 ou 24.36% de 700000, nous voyons donc que ces mêmes 25% du débit binaire perdu sont des baisses dans le socket udp. Les chutes dans un socket UDP se produisent généralement en raison d'un manque de tampon, regardez la taille du tampon de socket par défaut et la taille maximale du tampon de socket :

# sysctl net.core.rmem_default
net.core.rmem_default = 212992
# sysctl net.core.rmem_max
net.core.rmem_max = 212992

Ainsi, si les applications ne demandent pas explicitement une taille de buffer, les sockets sont créées avec un buffer de 208 Ko, mais si elles en demandent plus, elles ne recevront toujours pas ce qui a été demandé. Comme vous pouvez définir la taille du tampon dans tsp pour l'entrée IP (-buffer-size), nous n'allons pas toucher à la taille de socket par défaut, mais uniquement définir la taille maximale du tampon de socket et spécifier explicitement la taille du tampon via les arguments tsp :

sysctl net.core.rmem_max=8388608
ip netns exec P tsp --realtime -t -I ip 239.0.0.1:1234 -b 8388608 -P continuity -P bitrate_monitor -p 1 -t 1 -O drop

Avec ce réglage du tampon de socket, maintenant le débit binaire signalé est d'environ 100 Mbps, il n'y a pas d'erreurs CC.

Selon la consommation CPU de l'application tsp elle-même. Par rapport à un processeur i5-4260U à 1.40 GHz, l'analyse de flux à 10 Mbps nécessitera 3 à 4 % de processeur, 100 Mbps - 25 %, 200 Mbps - 46 %. Lors du réglage du % de perte de paquets, la charge sur le CPU n'augmente pratiquement pas (mais peut diminuer).

Sur du matériel plus productif, il était possible de générer et d'analyser des flux de plus de 1Gb/s sans aucun problème.

Test sur de vraies cartes réseau

Après avoir testé sur une paire veth, vous devez prendre deux hôtes ou deux ports d'un hôte, connecter les ports l'un à l'autre, démarrer le générateur sur l'un et l'analyseur sur le second. Il n'y a pas eu de surprise ici, mais en fait tout dépend du fer, plus il est faible, plus il sera intéressant ici.

Utilisation des données reçues par le système de surveillance (Zabbix)

tsp n'a pas d'API lisible par machine comme SNMP ou similaire. Les messages CC doivent être agrégés pendant au moins 1 seconde (avec un pourcentage élevé de perte de paquets, il peut y avoir des centaines/milliers/dizaines de milliers par seconde, selon le débit).

Ainsi, afin de sauvegarder à la fois les informations et de dessiner des graphiques pour les erreurs CC et le débit binaire et de créer des accidents, il peut y avoir les options suivantes :

  1. Analyser et agréger (par CC) la sortie de tsp, c'est-à-dire convertissez-le dans la forme souhaitée.
  2. Terminez tsp lui-même et/ou les plugins du processeur bitrate_monitor et continuité afin que le résultat soit donné sous une forme lisible par machine adaptée au système de surveillance.
  3. Écrivez votre application au-dessus de la bibliothèque tsduck.

De toute évidence, l'option 1 est la plus simple en termes d'effort, d'autant plus que tsduck lui-même est écrit dans un langage de bas niveau (selon les normes modernes) (C ++)

Un simple prototype d'analyseur bash + agrégateur a montré que sur un flux de 10 Mbps et 50% de perte de paquets (pire cas), le processus bash consommait 3 à 4 fois plus de CPU que le processus tsp lui-même. Ce scénario est inacceptable. En fait un morceau de ce prototype ci-dessous

Nouilles au top

#!/usr/bin/env bash

missingPackets=0
ccErrorSeconds=0
regexMissPackets='^* (.+) - continuity:.*missing ([0-9]+) packets$'
missingPacketsTime=""

ip netns exec P tsp --realtime -t -I ip -b 8388608 "239.0.0.1:1234" -O drop -P bitrate_monitor -p 1 -t 1  -P continuity 2>&1 | 
while read i
do
    #line example:* 2019/12/28 23:41:14 - continuity: packet index: 6,078, PID: 0x0100, missing 5 packets
    #line example 2: * 2019/12/28 23:55:11 - bitrate_monitor: 2019/12/28 23:55:11, TS bitrate: 4,272,864 bits/s
    if [[ "$i" == *continuity:* ]] 
    then
        if [[ "$i" =~ $regexMissPackets ]]
        then
            missingPacketsTimeNew="${BASH_REMATCH[1]}" #timestamp (seconds)
            if [[ "$missingPacketsTime" != "$missingPacketsTimeNew" ]] #new second with CC error
            then
                ((ccErrorSeconds += 1))
            fi
            missingPacketsTime=$missingPacketsTimeNew
            packets=${BASH_REMATCH[2]} #TS missing packets
            ((missingPackets += packets))
        fi
    elif [[ "$i" == *bitrate_monitor:* ]]
    then
        : #...
    fi
done

En plus d'être d'une lenteur inacceptable, il n'y a pas de threads normaux dans bash, les travaux bash sont des processus distincts et j'ai dû écrire la valeur de missingPackets une fois par seconde sur l'effet secondaire (lors de la réception de messages de débit qui arrivent toutes les secondes). En conséquence, bash a été laissé seul et il a été décidé d'écrire un wrapper (analyseur + agrégateur) dans golang. La consommation CPU d'un code golang similaire est 4 à 5 fois inférieure à celle du processus tsp lui-même. L'accélération du wrapper due au remplacement de bash par golang s'est avérée être d'environ 16 fois et en général le résultat est acceptable (surcharge CPU de 25% dans le pire des cas). Le fichier source golang se trouve ici.

Exécuter l'encapsuleur

Pour démarrer le wrapper, le modèle de service le plus simple pour systemd a été créé (ici). Le wrapper lui-même est censé être compilé dans un fichier binaire (go build tsduck-stat.go) situé dans /opt/tsduck-stat/. Il est supposé que vous utilisez golang avec prise en charge de l'horloge monotone (> = 1.9).

Pour créer une instance du service, vous devez exécuter la commande systemctl enable [email protected]:1234 puis exécuté avec systemctl start [email protected]: 1234.

Découverte de Zabbix

Pour que zabbix puisse découvrir les services en cours d'exécution, c'est fait générateur de liste de groupe (discovery.sh), dans le format requis pour la découverte Zabbix, on suppose qu'il se trouve au même endroit - dans /opt/tsduck-stat. Pour exécuter la découverte via zabbix-agent, vous devez ajouter fichier .conf au répertoire de configuration de zabbix-agent pour ajouter le paramètre utilisateur.

Modèle Zabbix

Modèle créé (tsduck_stat_template.xml) contient la règle de découverte automatique, les prototypes d'éléments, les graphiques et les déclencheurs.

Brève liste de contrôle (enfin, et si quelqu'un décide de l'utiliser)

  1. Assurez-vous que tsp ne laisse pas tomber de paquets dans des conditions "idéales" (le générateur et l'analyseur sont connectés directement), s'il y a des gouttes, voir le paragraphe 2 ou le texte de l'article à ce sujet.
  2. Réglez le tampon de socket maximal (net.core.rmem_max=8388608).
  3. Compilez tsduck-stat.go (allez construire tsduck-stat.go).
  4. Placez le modèle de service dans /lib/systemd/system.
  5. Démarrez les services avec systemctl, vérifiez que les compteurs ont commencé à apparaître (grep "" /dev/shm/tsduck-stat/*). Le nombre de services par le nombre de flux multicast. Ici, vous devrez peut-être créer une route vers le groupe de multidiffusion, peut-être désactiver rp_filter ou créer une route vers l'adresse IP source.
  6. Exécutez discovery.sh, assurez-vous qu'il génère json.
  7. Ajoutez la configuration de l'agent zabbix, redémarrez l'agent zabbix.
  8. Téléchargez le modèle sur zabbix, appliquez-le à l'hôte qui est surveillé et l'agent zabbix est installé, attendez environ 5 minutes, voyez s'il y a de nouveaux éléments, graphiques et déclencheurs.

Résultat

Utilisation de TSDuck pour surveiller les flux IP (TS)

Pour la tâche de détection de perte de paquets, c'est presque suffisant, du moins c'est mieux que pas de surveillance.

En effet, des «pertes» CC peuvent survenir lors de la fusion de fragments vidéo (pour autant que je sache, c'est ainsi que les insertions sont faites dans les centres de télévision locaux de la Fédération de Russie, c'est-à-dire sans recalculer le compteur CC), il faut s'en souvenir. Des solutions propriétaires contournent partiellement ce problème en détectant les labels SCTE-35 (si ajoutés par le générateur de flux).

En termes de surveillance de la qualité du transport, il y a un manque de surveillance de la gigue (IAT). Les équipements TV (qu'il s'agisse de modulateurs ou d'appareils terminaux) ont des exigences pour ce paramètre et il n'est pas toujours possible de gonfler le jitbuffer à l'infini. Et la gigue peut flotter lorsqu'un équipement avec de grandes mémoires tampons est utilisé en transit et que la QoS n'est pas configurée ou pas assez bien configurée pour transmettre un tel trafic en temps réel.

Source: habr.com

Ajouter un commentaire