Bruke TSDuck til å overvåke IP(TS)-strømmer

I dag finnes det ferdige (proprietære) løsninger for for eksempel overvåking av IP(TS)-strømmer VB и iQ, de har et ganske rikt sett med funksjoner og vanligvis har store operatører som driver med TV-tjenester slike løsninger. Denne artikkelen beskriver en løsning basert på et åpen kildekode-prosjekt TSDuck, designet for minimal kontroll av IP(TS)-strømmer med CC(continuity counter) teller og bitrate. En mulig applikasjon er å kontrollere tap av pakker eller hele flyten gjennom en leid L2-kanal (som ikke kan overvåkes normalt, for eksempel ved å lese taptellere i køer).

Veldig kort om TSDuck

TSDuck er en åpen kildekode (2-klausul BSD-lisens) programvare (et sett med konsollverktøy og et bibliotek for å utvikle tilpassede verktøy eller plugins) for å manipulere TS-strømmer. Som inngang kan den fungere med IP (multicast/unicast), http, hls, dvb tunere, dektec dvb-asi demodulator, det er intern TS-stream generator og lesing fra filer. Utgangen kan være skriving til en fil, IP (multicast/unicast), hls, dektec dvb-asi og HiDes modulatorer, spillere (mplayer, vlc, xine) og drop. Du kan aktivere ulike trafikkprosessorer mellom input og output, for eksempel PID-omtilordning, scrambling / descrambling, CC-telleranalyse, bitrateberegning og andre typiske operasjoner for TS-strømmer.

I denne artikkelen vil IP-strømmer (multicast) brukes som inngang, prosessorene bitrate_monitor (fra navnet er det tydelig hva det er) og kontinuitet (analyse av CC-tellere). Du kan enkelt erstatte IP multicast med en annen inngangstype som støttes av TSDuck.

Det er offisielle bygg/pakker TSDuck for de fleste aktuelle operativsystemer. De er ikke tilgjengelige for Debian, men vi klarte å bygge dem under debian 8 og debian 10 uten problemer.

Deretter brukes versjon TSDuck 3.19-1520, Linux brukes som OS (debian 10 ble brukt til å forberede løsningen, CentOS 7 ble brukt til reell bruk)

Forbereder TSDuck og OS

Før du overvåker reelle flyter, må du forsikre deg om at TSDuck fungerer riktig og at det ikke er noen fall på nettverkskortet eller OS (socket) nivå. Dette er nødvendig for ikke å gjette senere hvor fallene skjedde - på nettverket eller "inne på serveren". Du kan sjekke fall på nettverkskortnivå med ethtool -S ethX-kommandoen, tuning gjøres av samme ethtool (vanligvis må du øke RX-bufferen (-G) og noen ganger deaktivere noen avlastninger (-K)). Som en generell anbefaling kan det anbefales å bruke en egen port for å motta den analyserte trafikken, hvis mulig, dette minimerer falske positiver knyttet til det faktum at fallet skjedde nøyaktig på analysatorporten på grunn av tilstedeværelsen av annen trafikk. Hvis dette ikke er mulig (det brukes en mini-datamaskin/NUC med én port), så er det svært ønskelig å sette opp prioriteringen av den analyserte trafikken i forhold til resten på enheten som analysatoren er koblet til. Når det gjelder virtuelle miljøer, her må du være forsiktig og kunne finne pakkedråper som starter fra en fysisk port og slutter med en applikasjon inne i en virtuell maskin.

Generering og mottak av en strøm inne i verten

Som et første trinn i å forberede TSDuck, vil vi generere og motta trafikk innenfor en enkelt vert ved å bruke netns.

Forberede miljøet:

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

Miljøet er klart. Vi starter trafikkanalysatoren:

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

der "-p 1 -t 1" betyr at du må beregne bithastigheten hvert sekund og vise informasjon om bithastigheten hvert sekund
Vi starter trafikkgeneratoren med en hastighet på 10 Mbps:

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

der "-p 7 -e" betyr at du må pakke 7 TS-pakker inn i 1 IP-pakke og gjøre det hardt (-e), dvs. vent alltid 7 TS-pakker fra siste prosessor før du sender en IP-pakke.

Analysatoren begynner å sende ut de forventede meldingene:

* 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

Tilsett nå noen dråper:

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

og meldinger som dette vises:

* 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 

som er forventet. Deaktiver pakketap (ip netns exec P iptables -F) og prøv å øke generatorens bithastighet til 100 Mbps. Analysatoren rapporterer en haug med CC-feil og omtrent 75 Mbps i stedet for 100. Vi prøver å finne ut hvem som har skylden - generatoren har ikke tid eller problemet er ikke i den, for dette begynner vi å generere et fast antall pakker (700000 100000 TS-pakker = XNUMX XNUMX IP-pakker):

# 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

Som du kan se, ble nøyaktig 100000 151925460 IP-pakker generert (151825460-1). Så la oss finne ut hva som skjer med analysatoren, for dette sjekker vi med RX-telleren på veth0, den er strengt tatt lik TX-telleren på vethXNUMX, så ser vi på hva som skjer på socket-nivå:

# 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 

Her kan du se antall drops = 24355. I TS-pakker er dette 170485 eller 24.36% av 700000, så vi ser at de samme 25% av den tapte bithastigheten er fall i udp-socket. Fall i en UDP-socket oppstår vanligvis på grunn av mangel på buffer, se på standard socketbufferstørrelse og maksimal socketbufferstørrelse:

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

Således, hvis applikasjoner ikke eksplisitt ber om en bufferstørrelse, opprettes sockets med en buffer på 208 KB, men hvis de ber om mer, vil de fortsatt ikke motta det som ble forespurt. Siden du kan angi bufferstørrelsen i tsp for IP-inngangen (-buffer-størrelse), vil vi ikke berøre standard socket-størrelse, men bare angi maksimal socket-bufferstørrelse og spesifisere bufferstørrelsen eksplisitt gjennom tsp-argumentene:

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

Med denne innstillingen av socketbufferen, nå er den rapporterte bithastigheten omtrent 100 Mbps, er det ingen CC-feil.

I henhold til CPU-forbruket til selve tsp-applikasjonen. I forhold til én kjerne i5-4260U CPU @ 1.40 GHz, vil 10 Mbps flytanalyse kreve 3-4 % CPU, 100 Mbps – 25 %, 200 Mbps – 46 %. Når du angir % Packet Loss, øker ikke belastningen på CPU-en (men kan reduseres).

På mer produktiv maskinvare var det mulig å generere og analysere strømmer på mer enn 1 Gb/s uten problemer.

Testing på ekte nettverkskort

Etter å ha testet på et veth-par, må du ta to verter eller to porter på en vert, koble portene til hverandre, starte generatoren på den ene og analysatoren på den andre. Det var ingen overraskelser her, men faktisk avhenger alt av jernet, jo svakere, jo mer interessant blir det her.

Bruke de mottatte dataene fra overvåkingssystemet (Zabbix)

tsp har ikke noe maskinlesbart API som SNMP eller lignende. CC-meldinger må aggregeres i minst 1 sekund (med en høy prosentandel av pakketap kan det være hundrevis/tusenvis/ titusenvis per sekund, avhengig av bithastigheten).

For å lagre både informasjon og tegne grafer for CC-feil og bitrate og gjøre noen slags ulykker, kan det være følgende alternativer:

  1. Parse og aggreger (ved CC) produksjonen av tsp, dvs. konverter den til ønsket form.
  2. Fullfør tsp selv og/eller prosessorplugin bitrate_monitor og kontinuitet slik at resultatet blir gitt i en maskinlesbar form som passer for overvåkingssystemet.
  3. Skriv søknaden din på toppen av tsduck-biblioteket.

Åpenbart er alternativ 1 det enkleste når det gjelder innsats, spesielt med tanke på at tsduck i seg selv er skrevet på et lavt nivå (etter moderne standarder) språk (C ++)

En enkel bash-parser+aggregator-prototype viste at på en 10Mbps-strøm og 50 % pakketap (verste fall), forbrukte bash-prosessen 3-4 ganger mer CPU enn selve tsp-prosessen. Dette scenariet er uakseptabelt. Faktisk en del av denne prototypen nedenfor

Nudler på toppen

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

I tillegg til å være uakseptabelt treg, er det ingen normale tråder i bash, bash-jobber er separate prosesser og jeg måtte skrive verdien av missingPackets en gang i sekundet på bieffekten (når jeg mottar bitrate-meldinger som kommer hvert sekund). Som et resultat ble bash stående i fred og det ble besluttet å skrive en wrapper (parser + aggregator) i golang. CPU-forbruket av lignende golang-kode er 4-5 ganger mindre enn selve tsp-prosessen. Hastigheten på innpakningen på grunn av utskifting av bash med golang viste seg å være omtrent 16 ganger, og generelt er resultatet akseptabelt (CPU-overhead med 25 % i verste fall). Golang-kildefilen er lokalisert her.

Kjør wrapper

For å starte innpakningen ble den enkleste tjenestemalen for systemd laget (her). Selve innpakningen er ment å være kompilert til en binær fil (gå bygge tsduck-stat.go) som ligger i /opt/tsduck-stat/. Det antas at du bruker golang med støtte for monoton klokke (>=1.9).

For å opprette en forekomst av tjenesten, må du kjøre kommandoen systemctl enable [e-postbeskyttet]:1234 kjør deretter med systemctl start [e-postbeskyttet]: 1234.

Oppdagelse fra Zabbix

For at zabbix skal kunne oppdage løpende tjenester, er det gjort gruppelistegenerator (discovery.sh), i formatet som kreves for Zabbix-oppdagelse, antas det at det er plassert på samme sted - i /opt/tsduck-stat. For å kjøre oppdagelse via zabbix-agent, må du legge til .conf-fil til zabbix-agent-konfigurasjonskatalogen for å legge til brukerparameteren.

Zabbix mal

Laget mal (tsduck_stat_template.xml) inneholder autodiscover-regelen, elementprototyper, grafer og triggere.

Kort sjekkliste (vel, hva om noen bestemmer seg for å bruke den)

  1. Pass på at tsp ikke slipper pakker under "ideelle" forhold (generator og analysator er koblet direkte), hvis det er fall, se avsnitt 2 eller teksten i artikkelen om denne saken.
  2. Foreta innstilling av maksimal socketbuffer (net.core.rmem_max=8388608).
  3. Kompiler tsduck-stat.go (gå og bygg tsduck-stat.go).
  4. Sett tjenestemalen i /lib/systemd/system.
  5. Start tjenester med systemctl, sjekk at tellere har begynt å vises (grep "" /dev/shm/tsduck-stat/*). Antall tjenester etter antall multicast-strømmer. Her må du kanskje lage en rute til multicast-gruppen, kanskje deaktivere rp_filter eller lage en rute til kilde-ip.
  6. Kjør discovery.sh, sørg for at den genererer json.
  7. Legg til zabbix agent config, start zabbix agent på nytt.
  8. Last opp malen til zabbix, bruk den på verten som overvåkes og zabbix-agenten er installert, vent ca. 5 minutter, se om det er nye elementer, grafer og triggere.

Resultat

Bruke TSDuck til å overvåke IP(TS)-strømmer

For oppgaven med å oppdage pakketap er det nesten nok, i det minste er det bedre enn ingen overvåking.

Faktisk kan CC-"tap" oppstå ved sammenslåing av videofragmenter (så vidt jeg vet, er dette hvordan innlegg lages på lokale TV-sentre i Russland, dvs. uten å beregne CC-telleren på nytt), dette må huskes. Proprietære løsninger omgår delvis dette problemet ved å oppdage SCTE-35-etiketter (hvis lagt til av strømgeneratoren).

Når det gjelder overvåking av transportkvalitet, er det mangel på jitterovervåking (IAT). TV-utstyr (det være seg modulatorer eller sluttenheter) har krav til denne parameteren og det er ikke alltid mulig å blåse opp jitbufferen til det uendelige. Og jitter kan flyte når utstyr med store buffere brukes i transitt og QoS ikke er konfigurert eller ikke godt konfigurert nok til å overføre slik sanntidstrafikk.

Kilde: www.habr.com

Legg til en kommentar