Videostreaming per Multipath TCP

Dieser Artikel sollte mehr als „Proof of Concept“ verstanden werden. Ich bin weder ein Netzwerkspezialist, noch habe ich tiefgreifende Erfahrung mit Linux Kernel kompilieren.

Vorausgesetzt werden mindestens zwei Internetverbindungen, die Multipath TCP Verbindungen zulassen. Bei Internet über Kabel (Kabel Deutschland), hatte ich z.B. Probleme. Telekom sollte hier keine Probleme machen. Schreibt gerne auch, wenn ihr hier Erfahrungen gemacht habt.

Basis System ist Ubuntu 16.04, benötigt werden diese Pakete:

sudo apt install build-essential libssl-dev libncurses-dev ncurses-dev

Anschließend holt man sich den Kernel von github:

git clone --depth=1 git://github.com/multipath-tcp/mptcp.git

Konfiguriert ihn mit:

make menuconfig

Es sollten folgende Optionen aktiviert sein:

  • Networking support->Networking options->TCP/IP networking->MPTCP protocol (MPTCP)
  • Networking support->Networking options->TCP/IP networking->MPTCP: advanced scheduler control
    (alle aktivieren)
  • Networking support->Networking options->TCP: advanced congestion control->MPTCP Linked Increase
    (default habe ich hier: lia)
  • Networking support->Networking options->IP: advanced router->IP: policy routing (IP_MULTIPLE_TABLES)

Hier ist meine config: https://gist.github.com/jb-alvarado

Zum kompilieren verwende ich dieses Script:

#!/bin/bash

cd /usr/local/src/
rm -f *.deb

cd /usr/local/src/mptcp

sed -i 's/CONFIG_DEBUG_INFO=y/CONFIG_DEBUG_INFO=n/g' .config

DATE=`date "+%Y-%m-%d"`
KVERS=`make kernelversion`
make -j 3 deb-pkg DEBEMAIL='christoph.paasch@gmail.com' DEBFULLNAME='Christoph Paasch' LOCALVERSION=.mptcp KDEB_PKGVERSION=${DATE}

cd /usr/local/src/

# Create meta-package
rm -Rf linux-mptcp

mkdir linux-mptcp
mkdir linux-mptcp/DEBIAN
chmod -R a-s linux-mptcp
ctrl="linux-mptcp/DEBIAN/control"
touch $ctrl

echo "Package: linux-mptcp" >> $ctrl
echo "Version: ${DATE}" >> $ctrl
echo "Section: main" >> $ctrl
echo "Priority: optional" >> $ctrl
echo "Architecture: all" >> $ctrl
echo "Depends: linux-headers-${KVERS}.mptcp, linux-image-${KVERS}.mptcp" >> $ctrl
echo "Installed-Size:" >> $ctrl
echo "Maintainer: Christoph Paasch <christoph.paasch@gmail.com>" >> $ctrl
echo "Description: A meta-package for linux-mptcp" >> $ctrl

dpkg --build linux-mptcp

mv linux-mptcp.deb linux-mptcp_${DATE}_all.deb

Quelle: https://github.com/multipath-tcp/mptcp-scripts/blob/master/scripts/debian_build/create_kernel.sh

Pfade nach Bedürfnis anpassen.

Nach dem Kompilieren installieren:

sudo dpkg -i linux-firmware-image-4.4.83.mptcp_2017-08-21_amd64.deb linux-headers-4.4.83.mptcp_2017-08-21_amd64.deb
linux-image-4.4.83.mptcp_2017-08-21_amd64.deb linux-mptcp_2017-08-21_all.deb

und neu starten.

Wenn das System den neuen Kernel nicht als Default einrichtet, muss man das Händisch machen:

grep menuentry /boot/grub/grub.cfg

die Zeilen zählen beginnend mit 0, bis zum gewünschten Kernel. Ist das ganze in dem „Advanced options“ eingeklammert braucht man folgenden Eintrag in der Datei /etc/default/grub:

GRUB_DEFAULT=“1>ZeilenNummer“
# z.B.
GRUB_DEFAULT=“1>7″

Nach dem Neustart sollte mit uname -a in etwas das raus kommen:

Linux <computername> 4.4.83.mptcp #1 SMP Fri Aug 18 12:35:18 CEST 2017 x86_64 x86_64 x86_64 GNU/Linux

Als nächste kann man die multipath tcp Kernel Einstellungen prüfen:

sysctl -a | grep mptcp

Das Ergebnis sollte in etwas so sein:

net.mptcp.mptcp_checksum = 1
net.mptcp.mptcp_debug = 0
net.mptcp.mptcp_enabled = 1
net.mptcp.mptcp_path_manager = fullmesh
net.mptcp.mptcp_scheduler = default
net.mptcp.mptcp_syn_retries = 3
net.mptcp.mptcp_version = 0

Möchte man den default scheduler wechseln geht das mit:

sysctl -w net.mptcp.mptcp_scheduler=roundrobin

Bei mir ging roundrobin nur nach diesem Befehl:

sudo insmod /lib/modules/4.4.83.mptcp/kernel/net/mptcp/mptcp_rr.ko

Laut Doku wird roundrobin nicht empfohlen.

redundant wird nur empfohlen wenn man sehr niedrige Latencen möchte, und verbrauchte mbit keine Rolle spielen.

Weitere Optimierungen gibt es hier: ConfigureMPTCP

Nun braucht es noch ein Routing:

der Einfachheit halber gehen wir von eth0 und eth1 aus. Dann könnte ein Script dafür in etwa so aussehen:

#!/bin/bash

devArr=("eth0" "eth1")
ipArr=("192.168.0.2" "172.20.10.2")
gatArr=("192.168.0.1" "172.20.10.1")

# reset all routes
for ((i=0; i < ${#devArr[@]}; i++)); do
        ip route del default dev ${devArr[$i]} 2>/dev/null
        ip rule del from 0/0 to 0/0 table $((i+1)) 2>/dev/null
        ip route flush table $((i+1)) 2>/dev/null
done

# add rules and routes
for ((i=0; i < ${#devArr[@]}; i++)); do
        ip rule add from ${ipArr[$i]} table $((i+1))
        ip route add $( awk -F. '{ print $1"."$2"."$3".0/24" }' <<< ${ipArr[$i]} ) dev ${devArr[$i]} scope link table $((i+1))
        ip route add default via ${gatArr[$i]} dev ${devArr[$i]} table $((i+1))
done

# default route for the selection process of normal internet-traffic
ip route add default scope global nexthop via ${gatArr[0]} dev ${devArr[0]}


exit 0

Ist noch kein schönes Script, besser wären zwei unter /etc/network/if-down.d/ und /etc/network/if-up.d/

Sind die Routen angelegt noch mal prüfen:

$ ip route
default via 192.168.0.1 dev eth0 
172.20.10.0/28 dev eth1  proto kernel  scope link  src 172.20.10.2  metric 100 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.2  metric 600
$ ip rule
0:	from all lookup local 
32764:	from 172.20.10.2 lookup T2 
32765:	from 192.168.0.2 lookup T1 
32766:	from all lookup main 
32767:	from all lookup default
$ ip route show table 1
default via 192.168.0.1 dev eth0 
192.168.0.0/24 dev eth0  scope link 

$ ip route show table 2
default via 172.20.10.1 dev eth1 
172.20.10.0/24 dev eth1  scope link

Um nun eine Videostream über multipath tcp laufen zu lassen, braucht es auf der Empfängerseite noch einen Kernel der auch multipath tcp versteht. Allerdings reicht es hier die kompilierte Version zu installieren und aktivieren. Alles ander kann gespart werden.

Als Streamingserver bietet sich srs an.

Streamen könnte man dann in etwa so:

ffmpeg -re -i test.mp4 -s 320x180 -c:v libx264 -crf 26 -preset slower -c:a aac -b:a 92k -ar 44100 -f flv "rtmp://example.org:1935/live/mptcp"

Anschauen würde so gehen:

ffplay "rtmp://example.org:1935/live/mptcp"

Achtung: streamt man auf einen Domainnamen, braucht man einen korrekten „Reverse DNS Eintrag“, hat man den nicht besser die IP nehmen.

Prüfen ob über beide Verbindungen Traffic läuft kann man auf der Senderseite mit:

sudo tcpdump -i any tcp and dst host example.org and dst port 1935 -nq

und auf der Empfängerseite mit:

sudo tcpdump -i eth0 tcp and dst host 192.168.100.50 and port 1935 -nq

Wird nur über eine IP gesendet, stimmt was nicht, ansonsten hat man es geschafft :).

Wenn wir nun ein Interface blocken, sollte der Stream munter weiter streamen:

iptables -A OUTPUT -o eth0 -j DROP

Wenn das der Fall ist kann die iptables Regel wieder entfernt werden:

iptables -D OUTPUT -o eth0 -j DROP

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.