A TSDuck használata IP(TS) folyamok figyelésére.

Jelenleg léteznek kész (szabadalmazott) megoldások IP(TS) folyamok monitorozására, például VB és iQ, amelyek viszonylag gazdag funkciókészlettel rendelkeznek, és általában az ilyen megoldások a nagyobb szolgáltatóknál megtalálhatók, akik TV-szolgáltatásokkal foglalkoznak. Ebben a cikkben egy open source projekt alapú megoldást mutatunk be, TSDuck, amely az IP(TS) folyamok minimális ellenőrzésére szolgál a CC (folytonossági számláló) és a bitráta alapján. Egy lehetséges alkalmazási terület a csomagok vagy az egész folyam elvesztésének figyelése egy bérelt L2-csatornán (amelyet nem lehet szabványosan monitorozni, például a sorokban lévő elvesztési számlálók leolvasásával).

Röviden a TSDuck-ról

A TSDuck egy open source (2-Clause BSD licenc) szoftver (parancssori segédprogramok és könyvtár fejlesztéshez saját segédprogramokhoz vagy bővítményekhez), amely TS-folyamokkal való manipulációra alkalmas. Bemenetként képes IP (multicast/unicast), http, hls, dvb-tuner, dektec dvb-asi demodulátorral dolgozni, van egy belső TS-folyam generálója és fájlokból olvas. Kimenetként lehet fájlba írni, IP (multicast/unicast), hls, dektec dvb-asi és HiDes modulátorok, lejátszók (mplayer, vlc, xine) és drop. A bemenet és a kimenet között különböző forgalmi processzorok helyezhetők el, például PID-mapping, scrambling/descrambling, CC-számlálók elemzése, bitráta számolás és egyéb tipikus TS-folyam műveletek.

Ebben a cikkben bemenetként IP folyamokat (multicast) fogunk használni, a bitrate_monitor (a névből már egyértelmű, hogy mire való) és a continuity (CC-számlálók analízise) processzorokat alkalmazva. IP multicast helyett könnyen lehet más, a TSDuck által támogatott bemeneti típust is használni.

Elérhetők hivatalos összeállítások/csomagok a TSDuck-hoz a legtöbb aktuális operációs rendszerhez. Debianra nem állnak rendelkezésre, de sikerült problémamentesen összeállítani Debian 8 és Debian 10 alatt.

A használt TSDuck verzió 3.19-1520, az operációs rendszer pedig Linux (a megoldás előkészítéséhez Debian 10-et használtak, a valódi használathoz pedig CentOS 7-et)

A TSDuck és az operációs rendszer előkészítése

Mielőtt valós forgalmat monitorálnánk, győződjünk meg arról, hogy a TSDuck helyesen működik, és hogy nincsenek kiesések a hálózati kártya vagy az operációs rendszer (socket) szintjén. Erre azért van szükség, hogy később ne kelljen találgatni, hogy hol történtek a kiesések — a hálózaton vagy a "szerver belsejében". A hálózati kártya szintjén a kieséseket az ethtool -S ethX paranccsal ellenőrizhetjük, a finomhangolás ugyanazzal az ethtool-lal végezhető (általában az RX-puffer növelésére (-G) és néha bizonyos offload-ok kikapcsolására (-K) van szükség). Általános ajánlásként érdemes külön portot használni az elemzett forgalom fogadására, ha van ilyen lehetőség, mivel ez minimalizálja a téves riasztásokat, amelyek abból adódhatnak, hogy a kiesés éppen az analóg portnál történt a másik forgalom miatt. Ha nincs ilyen lehetőség (például egyetlen portos mini számítógép/NUC használatakor), akkor nagyon fontos beállítani az elemzett forgalom priorizálását a többi forgalomhoz képest azon az eszközön, amelyhez az analizátor csatlakozik. A virtuális környezettel kapcsolatban óvatosnak kell lenni, és tudni kell, hogyan találhatók a csomagkiesések a fizikai porttól kezdve egészen a virtuális gépen belüli alkalmazásig.

Áramlás generálása és fogadása a hoszton belül

Első lépésként a TSDuck előkészítése érdekében belső forgalmat generálunk és fogadunk egy hoszton belül netns használatával.

Környezet előkészítése:

ip netns add P # létrehozzuk a netns P-t, ahol a forgalom elemzése zajlik
ip link add type veth # létrehozzuk a veth párt - a veth0 a netns-ben marad a default (ebben az interfészben fog generálódni a forgalom)
ip link set dev veth1 netns P # a veth1-et a netns P-be helyezzük (ezen az interfészen fogadjuk a forgalmat)
ip netns exec P ifconfig veth1 192.0.2.1/30 up # az IP aktiválása a veth1-en, nem számít, hogy pontosan melyik
ip netns exec P ip ro add default via 192.0.2.2 # az alapértelmezett útvonal beállítása a netns P-n belül
sysctl net.ipv6.conf.veth0.disable_ipv6=1 # az IPv6 kikapcsolása a veth0-n - ezt azért tesszük, hogy a TX számlálóba ne kerüljön kéretlen zaj
ifconfig veth0 up # a veth0 interfész aktiválása
ip route add 239.0.0.1 dev veth0 # létrehozunk egy útvonalat, hogy az operációs rendszer a forgalmat a 239.0.0.1 felé irányítsa a veth0 irányába

A környezet készen áll. Indítjuk a forgalomelemzőt:

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

ahol a „-p 1 -t 1” azt jelenti, hogy a bitrátát minden másodpercben kiszámítjuk és minden másodpercben megjelenítjük az információt a bitrátáról
Indítjuk a forgalomgenerátort 10 Mbit/s sebességgel:

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

ahol a „-p 7 -e” azt jelenti, hogy 7 TS-csomagot kell egy IP-csomagba csomagolni, és ezt szigorúan (-e), azaz mindig meg kell várni az utolsó processzortól a 7 TS-csomag elküldését az IP-csomag formálásához.

Az elemző elkezdi az elvárt üzenetek kiadását:

* 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

Most hozzáadunk egy kis csomagvesztést:

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

és olyan üzenetek jelennek meg, mint ezek:

* 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 

ami várható. Kikapcsoljuk a csomagvesztést (ip netns exec P iptables -F), és megpróbáljuk növelni a generátor bitrátáját 100 Mbit/s-ra. Az elemző sok CC-hibát rögzít és körülbelül 75 Mbit/s-t jelez a 100-ból. Megpróbáljuk kideríteni, hogy a generátor nem bírja el, vagy van más probléma, ezért elindítjuk a fix mennyiségű csomag (700000 TS-csomag = 100000 IP-csomag) generálását:

# 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

Ahogy látható, pontosan 100000 IP-csomag lett generálva (151925460-151825460). Ezért megnézzük, mi történik az elemzővel, ehhez összehasonlítjuk az RX számlálót a veth1-en, amely pontosan egyenlő a TX számlálóval a veth0-n, majd megnézzük, mi történik a socket szintjén:

# 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 

Itt látható, hogy a vesztett csomagok száma = 24355. A TS-csomagokban ez 170485, vagyis a 700000-ből 24,36%. Tehát látjuk, hogy a 25%-os bitráta-veszteség ez a UDP-socketben keletkezett csomagvesztés. A UDP-socketek gyakran sávszélességhiány miatt veszítenek. Nézzük meg, mekkora az alapértelmezett socketbuffer mérete és a maximális socketbuffer méret:

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

Így, ha az alkalmazások nem kérik egyértelműen a buffer méretét, a socketek 208 Kb méretű bufferrel jönnek létre. De ha nagyobb méretet kérnek, akkor mégsem kapják meg. Mivel a tsp ip bemenetnél megadhatunk buffer méretet (—buffer-size), nem érintjük az alapértelmezett socket méretét, hanem csak a maximális buffer méretet állítjuk be és megadjuk a buffer méretét a tsp argumentumokon keresztül:

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

Ezzel a socket buffer optimalizálással a jelentett bitráta most körülbelül 100 Mbit/s, és nincs CC-hiba.

A CPU usage of the application tsp. For a single i5-4260U CPU @ 1.40GHz core, analyzing a 10 Mbps stream requires 3-4% CPU, 100 Mbps — 25%, 200 Mbps — 46%. When setting the packet loss percentage, the CPU load does not significantly increase (but can decrease).

On more powerful hardware, it was possible to generate and analyze streams of over 1 Gbps without any problems.

Testing on real network cards

After testing on a veth pair, you need to take two hosts or two ports of one host, connect the ports to each other, run the generator on one, and the analyzer on the other. There were no surprises here, but it really depends on the hardware; the weaker it is, the more interesting it will be.

Using the collected data with the monitoring system (Zabbix)

The tsp does not have any machine-readable API like SNMP or similar. CC messages need to be aggregated at least every second (with a high packet loss percentage, there can be hundreds/thousands/ten thousands per second, depending on the bitrate).

Thus, to store both information and draw graphs for CC errors and bitrate and handle some incidents further, the following options may be available:

  1. Parse and aggregate (by CC) the tsp output, meaning transforming it into the required format.
  2. Enhance tsp itself and/or the processor plugins bitrate_monitor and continuity, so that the result is provided in a machine-readable format suitable for the monitoring system.
  3. Write your own application on top of the tsduck library.

Clearly, option 1 requires the least effort, especially considering that tsduck itself is written in a low-level language (relative to modern standards) (C++).

A simple prototype of a parser+aggregator in bash showed that at a 10 Mbps stream and 50% packet loss (the worst case), the bash process consumed 3-4 times more CPU than the tsp process itself. Such an outcome is unacceptable. A piece of this prototype is below.

Noodles on bash

#!/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

Amiatt, hogy ez elfogadhatatlanul lassan működik, a bash-ból hiányoznak a normális szálak, a bash feladatok önálló folyamatok, és másodpercenként kellett rögzíteni a missingPackets értékét egy mellékhatással (amikor a bitrátáról érkező üzenetek jönnek másodpercenként). Ennek eredményeként a bash-t magára hagyták, és úgy döntöttek, hogy egy wrapper-t (parser+aggregátor) írnak golang nyelven. Az azonos kód CPU-fogyasztása golang nyelven 4-5-ször kevesebb, mint a tsp folyamaté. A wrapper gyorsasága, azáltal, hogy a bash-t golang-ra cserélik, körülbelül 16-szoros lett, és összességében az eredmény elfogadható (a CPU overhead a legrosszabb esetben 25%). A golang forrásfájl itt található itt.

A wrapper elindítása

A wrapper elindításához egy egyszerű service sablont készítettek a systemd számára (itt). Feltételezve, hogy a wrapper le lett fordítva egy bináris fájlba (go build tsduck-stat.go), amely a \/opt\/tsduck-stat\/ mappában található. Az is feltételezhető, hogy a golang támogatja a monotonic clock-ot (>=1.9).

A service példány létrehozásához hajtsa végre a systemctl enable tsduck-stat@239.0.0.1:1234 parancsot, majd indítsa el a systemctl start tsduck-stat@239.0.0.1:1234 parancsal.

Felfedezés a Zabbix-ból

Ahhoz, hogy a Zabbix felfedezhesse az elindított szolgáltatásokat, készült egy csoportlista-generátor (discovery.sh), a Zabbix felfedezéséhez szükséges formátumban, amely itt is található — a \/opt\/tsduck-stat mappában. A felfedezés Zabbix-ügynökön keresztüli futtatásához hozzá kell adni .conf-fájlt a Zabbix-ügynök konfigurációs mappájába a user-paraméter hozzáadásához.

Zabbix sablon

A létrehozott sablon (tsduck_stat_template.xml) tartalmazza az automatikus felfedezés szabályát, adatelemek, grafikonok és riasztások prototípusait.

Rövid ellenőrzőlista (hátha valaki használni akarja)

  1. Győződjön meg arról, hogy a tsp nem ejesdik csomagokat "tökéletes" körülmények között (a generátor és elemző közvetlenül csatlakozik), ha vannak ejesdési problémák, lásd a 2. pontot vagy a cikk szövegét erről.
  2. Szabályozza a maximális socket puffer méretet (net.core.rmem_max=8388608).
  3. Fordítsa le a tsduck-stat.go-t (go build tsduck-stat.go).
  4. Helyezze el a service sablont a \/lib\/systemd\/system mappába.
  5. Indítsa el a szolgáltatásokat a systemctl segítségével, és ellenőrizze, hogy elkezdtek-e megjelenni a számlálókkal (grep "" \/dev\/shm\/tsduck-stat\/*). A szolgáltatások száma a multicast áramlások számával egyezik meg. Itt szükség lehet egy útvonal létrehozására a multicast csoportra, lehet, hogy ki kell kapcsolni az rp_filter-t, vagy szükség van egy útvonal létrehozására a source ip-hez.
  6. Futtassa a discovery.sh-t, és ellenőrizze, hogy generál-e json-t.
  7. Helyezze el a Zabbix-ügynök konfigurációját, majd indítsa újra a Zabbix-ügynököt.
  8. Töltsön le egy sablont a Zabbix rendszerből, alkalmazza azt a hostra, amelyen a megfigyelést végzik és a zabbix-agent telepítve van, várjon körülbelül 5 percet, majd nézze meg, hogy új adatelemek, grafikonok és triggerek jelentek-e meg.

Eredmény

A TSDuck használata IP(TS) folyamok figyelésére.

A csomagvesztés észleléséhez szinte elegendő, de jobb, mint a megfigyelés hiánya.

Valóban, a CC-'veszteségek' előfordulhatnak videórészletek összeillesztésénél (ahogy tudom, így készülnek a betétek a helyi televíziós központokban Oroszországban, azaz a CC-számláló újraszámolása nélkül), ezt érdemes szem előtt tartani. A tulajdonosi megoldások esetén részben megkerülhető ez a probléma az SCTE-35 címkék detektálásával (ha azokat a stream-generátor hozzáadja).

A szállítási minőség megfigyelésének szempontjából hiányzik a jitter (IAT) monitorozása, mivel a TV-berendezések (akár modulátorok, akár végberendezések) követelményeket támasztanak e paraméterrel kapcsolatban, és nem mindig lehet végtelenségig kitágítani a jitbuffert. A jitter eltérhet, ha az átvitelnél nagy pufferekkel rendelkező berendezést használnak, és a QoS nincs megfelelően beállítva az ilyen valós idejű forgalom átvitelére.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster