Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Für alle Technik-Themen bezogen auf Internet und Telefonie, die weder AVM- noch Arris-/Technicolor-/Compal-/Sagemcom-/Hitron-Produkte betreffen. Speedprobleme werden hier lediglich thematisiert, wenn sie auf die verwendeten Geräte zurückzuführen sind (die nicht zu den o.g. Produkten zählen).
Forumsregeln
Forenregeln
robert_s
Insider
Beiträge: 3526
Registriert: 30.11.2010, 15:09

Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Beitrag von robert_s » 12.12.2018, 01:39

Mit dem Gigabit-Tarif liefert Vodafone Kabel mehr Bits/s als ein Gigabit-Ethernet-Port übertragen kann. Wie kann man also den Anschluss mit einem Gerät voll ausreizen? Indem man zwei Gigabit-Ethernet-Ports verwendet 8) Mein derzeitiger Desktop-PC hat passenderweise schon zwei LAN-Ports auf dem Mainboard, und zwei LAN-Verbindungen zum Router hatte ich auch zur Verfügung.

Aber die Nutzung dieser Möglichkeit gestaltete sich doch deutlich schwieriger als ich gedacht hatte. Einen Kabelrouter mit Link Aggregation gibt es leider noch nicht, also muss man ein "autarkes" Load Balancing basteln, welches keine Zusammenarbeit vom Router benötigt. Ich habe zwei Tage intensiver Internet-Recherche und Tüftelei gebraucht, bis ich mir dieses Script erarbeitet hatte, um Ubuntu 16.04 LTS zu überreden, beide LAN-Verbindungen zu nutzen:

Code: Alles auswählen

#!/bin/bash
# load balancing configuration script for Ubuntu/Linux 16.04 LTS
# currently only IPv4 and only in downstream direction

# the interfaces to be load-balanced
IF1=eno1
IF2=eno2

function clear_routes() {
	local RT=$1

	while read ROUTE
	do
		sudo ip route del $ROUTE table $RT
	done < <(ip route list table $RT)
}

function copy_routes() {
	local RT=$1
	local IF=$2
	local IP=0.0.0.0

	while read ROUTE
	do
		sudo ip route add $ROUTE table $RT
		if [[ "$ROUTE" == *" src "* ]]; then
			IP=`echo $ROUTE | grep -o "src \S*" | cut -d' ' -f2`
		fi
	done < <(ip route list table main | grep " dev $IF ")

	echo $IP
}

function clear_rules() {
	local RT=$1

	while read RULE
	do
		sudo ip rule del table $RT
	done < <(ip rule list | grep "^$RT:")
}

function setup_route_table() {
	local RT=$1
	local IF=$2

	clear_routes $RT
	IP=$(copy_routes $RT $IF)

	clear_rules $RT
	sudo ip rule add from $IP prio $RT table $RT

	sudo sysctl -q -w net.ipv4.conf.$IF.arp_filter=1
	sudo sysctl -q -w net.ipv4.conf.$IF.rp_filter=2

	echo $IP
}

function clear_route_table() {
	local RT=$1
	local IF=$2

	sudo sysctl -q -w net.ipv4.conf.$IF.arp_filter=0
	sudo sysctl -q -w net.ipv4.conf.$IF.rp_filter=1

	clear_rules $RT

	clear_routes $RT
}

function enable_load_balancing() {
	# set up ip routes
	IP1=$(setup_route_table 1 $IF1)
	IP2=$(setup_route_table 2 $IF2)
	sudo ip route flush cache

	# set up iptables to randomly swap the source IP addresses
	sudo iptables -F -t nat
	sudo iptables -A POSTROUTING -t nat -o $IF1 -m statistic --mode random --probability 0.5 -j SNAT --to-source $IP2
	sudo iptables -A POSTROUTING -t nat -o $IF2 -m statistic --mode random --probability 0.5 -j SNAT --to-source $IP1
}

function disable_load_balancing() {
	sudo iptables -F -t nat
	clear_route_table 1 $IF1
	clear_route_table 2 $IF2
	sudo ip route flush cache
}

function show_load_balancing() {
	echo "Load balancing statistics (pkts bytes):"
	sudo iptables -L POSTROUTING -t nat -v | grep "statistic"
}

set -e

case $1 in
on|enable)
	enable_load_balancing
	;;
off|disable)
	disable_load_balancing
	;;
"")
	show_load_balancing
	;;
*)
	echo "Usage: $0 [on|off] - enable or disable load balancing over $IF1 and $IF2"
	;;
esac
Anpassen muss man ggf. die Zeilen IF1 und IF2, je nachdem, wie die LAN-Ports (=Netzwerkinterfaces) im System heißen - das ist hardwareabhängig, häufig heißen sie "eth0" und "eth1", können aber auch sowas wie "enps025" heißen. Ggf. findet man das mit "ifconfig -a" raus.

Außerdem sollte man IPv6 für beide LAN-Verbindungen deaktivieren. Das kann man in Ubuntu über die GUI machen, indem man die Verbindungen editiert und unter dem Reiter "IPv6" oben "Ignore" auswählt.

Dann kann man das Script, wenn man es z.B. als "load_balancing" gespeichert und ausführbar gemacht hat so nutzen:

load_balancing on - konfiguriert load-balancing
load_balancing off - entfernt die load-balancing Konfiguration
load_balancing - zeigt etwas Status von iptables an. Eigentlich wenig interessant

Übrigens sind keine von den Änderungen persistent! Wenn das Script einem also die Netzwerkkonfiguration "zerschiessen" sollte und man gar kein Internet mehr hat, einfach neu booten und alles ist wie vorher.

Zur Historie und Funktionsweise:

Das erste Problem ist, dass beide LAN-Verbindungen im selben Subnetz liegen und denselben Gateway haben. Damit kann Linux so gar nichts anfangen, das kennt immer nur einen Pfad zu einem Gateway. Entsprechend legt es von sich aus Routingeinträge mit unterschiedlicher "metric" an - was dazu führt, dass eine LAN-Verbindung immer genutzt wird und die andere nie (bzw. erst, wenn man die genutzte trennt). Es ist auch nicht möglich, beide auf die gleiche "metric" zu setzen.

Um also die beiden LAN-Verbindungen überhaupt nutzen zu können, muss man erst mal das Routing umstricken: Linux erlaubt zwar nicht zwei Pfade zum gleichen Gateway in einer Routingtabelle - aber es erlaubt mehrere Routingtabellen! Also legt die Funktion setup_route_table() für je eine LAN-Verbindung eine eigene Routingtabelle an, wo nur eines der beiden Netzwerkinterfaces vorkommt. Dazu wird ein "ip rule" angelegt, was festlegt, dass Pakete, welche die IP-Adresse dieses Netzwerkinterfaces haben, über dessen eigene Routingtabelle zu routen sind - fertig ist das sogenannte "source based routing".

Nun kann man mit "ping -I <Netzwerkinterface|dessen zugewiesene IP-Adresse> <Ziel>" über die eine oder andere LAN-Verbindung pingen.

Nur wählen lokale Anwendungen typischerweise das "Default" Netzwerkinterface für ihre Kommunikation aus, und entsprechend geht sämtlicher Datenverkehr immer noch nur über eine LAN-Verbindung (nämlich immer noch die mit der anfangs erwähnten niedrigeren "metric").

Dem wird mit den mächtigen "iptables" Abhilfe geleistet, mit welchen sich Routingalgorithmen quasi "programmieren" lassen. Da ich iptables aber gerade mal Ansatzweise verstehe, habe ich etwas eigentlich recht Simples eingerichtet: Mit 50%iger Wahrscheinlichkeit wird die Quelladresse eines über ein Netzwerkinterface gesendeten Pakets mit der Quelladresse des anderen Netzwerkinterfaces ausgetauscht. Streng genommen ist das "IP spoofing", aber meinen Kabelrouter hat es nicht gestört :twisted: Nötig wäre das eigentlich nur für das eine Netzwerkinterface, über das sämtlicher Datenverkehr geht, aber da man nicht vorhersagen kann, welches von den beiden ist (das hängt von der Initialisierungsreihenfolge oder der Reihenfolge beim Einstecken der LAN-Kabel ab und kann bei einem Reboot auch mal wechseln), wird es für beide aufgesetzt - angewendet wird stets nur eins von beiden.

Und damit kommen wir auch schon zu den berühmten

Known Issues:

1. Es funktioniert nur für IPv4
2. Es funktioniert nur für den Downstream, der Upstream läuft stets komplett über das Netzwerkinterface mit der niedrigeren "metric".
3. Es funktioniert nur "statisch", d.h. man muss vor dem Einschalten des load-balancing beide LAN-Verbindungen hergestellt haben, und sollte es auch besser abschalten, wenn man eine der beiden Verbindungen trennen möchte.

Punkt 2 und auch das unschöne "IP spoofing" könnte man beheben, indem man ein virtuelles Netzwerkinterface aufsetzt und das zum Default macht (durch Setzen der Defaultroute mit der niedrigsten "metric"), und dann iptables so einrichtet, dass es eine Art "inverses NAT" auf die beiden echten Netzwerkinterfaces macht. Das sollte eigentlich machbar sein.

Punkt 3 könnte man auch beheben, indem man up/down Hook-Scripte für die beiden Netzwerkinterfaces baut, die dann entsprechend das Routing umkonfigurieren, wenn eine LAN-Verbindung getrennt wird oder hinzukommt.

Also wer mag, und sich vielleicht mit iptables besser auskennt als ich, darf gerne an dem Script weiter tüfteln. Viel Spaß! :grin:

Flole
Kabelfreak
Beiträge: 1500
Registriert: 31.12.2015, 01:11

Re: Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Beitrag von Flole » 12.12.2018, 02:01

Es gibt Link Aggregation ohne LACP, das hätte es auch getan ;)

robert_s
Insider
Beiträge: 3526
Registriert: 30.11.2010, 15:09

Re: Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Beitrag von robert_s » 12.12.2018, 02:07

Flole hat geschrieben:
12.12.2018, 02:01
Es gibt Link Aggregation ohne LACP, das hätte es auch getan ;)
Habe ich mir vorher angeschaut, und ich denke das funktioniert nicht. Die Bonding-Modi, welche keine Unterstützung von dem Switch(Router) benötigen basieren darauf, dass man mit unterschiedlichen Gegenstellen spricht. Der Router ist im NAT-Fall aber die einzige Gegenstelle, und selbst mit IPv6 würdest Du damit im Speedtest oder beim Multi-Stream-Download nicht das Gigabit-Ethernet-Limit knacken, weil Du dann ja auch nur mit einer Gegenstelle sprichst.

Flole
Kabelfreak
Beiträge: 1500
Registriert: 31.12.2015, 01:11

Re: Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Beitrag von Flole » 12.12.2018, 02:23

Modus 6 wäre es gewesen, und den hast du im Prinzip nachgebaut (nur schlechter): Bei Mode 6 wird das am wenigsten ausgelastete Interface benutzt, du teilst "gleich" auf, egal obs Sinn macht oder nicht.

Es gibt aber ein großes Problem was ich da sehe: Die ARP Anfragen werden normalerweise gecached, also bringt bei einer Gegenstelle (Router/Modem) das ganze wenig. Bei einem Modem dürfte es auch Probleme mit MaxCPE gebe, bei einem Router cached der deine ARP Ergebnisse, auch etwas blöd. Obs tatsächlich nicht funktioniert weiß ich nicht, es ist einfach eine Vermutung basierend auf Erkenntnissen und viel Erfahrung.

sch4kal
Kabelexperte
Beiträge: 626
Registriert: 22.03.2018, 15:14

Re: Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Beitrag von sch4kal » 12.12.2018, 08:40

Könnte man so umgekehrt auch mit IPVS nachbauen, wahrscheinlich performanter.

Abraxxas
Kabelfreak
Beiträge: 1939
Registriert: 24.08.2010, 21:10
Wohnort: 67117

Re: Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Beitrag von Abraxxas » 12.12.2018, 09:18

War die Arbeit nun von Erfolg gekrönt? Ist der Durchsatz von ~900 auf 1000MBit/s gestiegen? Darum gings doch.

Habe dazu diesen 10 Jahre alten Artikel gefunden. https://www.linux.com/news/what-can-you ... ernet-port
Dort liest sich das viel einfacher mittels des ifensalve package.

robert_s
Insider
Beiträge: 3526
Registriert: 30.11.2010, 15:09

Re: Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Beitrag von robert_s » 12.12.2018, 16:35

Flole hat geschrieben:
12.12.2018, 02:23
Modus 6 wäre es gewesen, und den hast du im Prinzip nachgebaut (nur schlechter): Bei Mode 6 wird das am wenigsten ausgelastete Interface benutzt, du teilst "gleich" auf, egal obs Sinn macht oder nicht.

Es gibt aber ein großes Problem was ich da sehe: Die ARP Anfragen werden normalerweise gecached, also bringt bei einer Gegenstelle (Router/Modem) das ganze wenig. Bei einem Modem dürfte es auch Probleme mit MaxCPE gebe, bei einem Router cached der deine ARP Ergebnisse, auch etwas blöd. Obs tatsächlich nicht funktioniert weiß ich nicht, es ist einfach eine Vermutung basierend auf Erkenntnissen und viel Erfahrung.
Wie Du eigentlich selbst schreibst - es kann gar nicht funktionieren. Der ganze Mechanismus beruht darauf, dass Du ARP-Anfragen wechselweise beantwortest. Du hast aber sowohl im Router- als auch im Bridge-Modus immer nur eine Gegenstelle (entweder den Router oder das CMTS), welche Dir ARP-Anfragen schickt. Entsprechend würdest Du da immer den gesamten Traffic von einer Verbindung auf die andere umschalten, aber nie aufteilen.

Aber ich habe auch nichts dagegen, wenn Du einen besseren Weg findest. Dafür brauchst Du ja auch gar keinen Gigabit-Anschluss - ich habe das obige Script auch noch mit meinem 200Mbit/s Anschluss entwickelt, und mit "speedometer" mir den Durchsatz auf beiden Netzwerkinterfaces angeschaut, bis ich es endlich geschafft hatte, dass ein Speedtest auf www.speedtest.net Traffic auf beiden Interfaces erzeugt. Also wenn Du es mit dem Linux Bonding-Treiber schaffst, den Traffic zwischen Kabelrouter und PC auf zwei LAN-Verbindungen aufzuteilen, dann bringe das gerne in diesen Thread ein.
Abraxxas hat geschrieben:
12.12.2018, 09:18
Habe dazu diesen 10 Jahre alten Artikel gefunden. https://www.linux.com/news/what-can-you ... ernet-port
Dort liest sich das viel einfacher mittels des ifensalve package.
Das ist das Linux Bonding, von dem auch @Flole schreibt, und das meiner Ansicht nach eben nicht funktioniert. Wenn man einen Kabelrouter/-modem hat, welches LACP (IEEE802.3ad) beherrscht, dann kann man das mit Bonding Mode 4 verwenden, aber m.W. gibt es derzeit nur ein Kabelmodem, welches LACP kann, und von dem gibt es leider keine EuroDOCSIS-Variante: https://motorolanetwork.com/mb8600.html
Abraxxas hat geschrieben:
12.12.2018, 09:18
War die Arbeit nun von Erfolg gekrönt? Ist der Durchsatz von ~900 auf 1000MBit/s gestiegen? Darum gings doch.
Achso, hatte das nur in einem anderen Forum gepostet:

speedtest.net ohne Bonding:
Speedtest-Result-20181211_7872568102.png
speedtest.net mit Bonding:
Speedtest-Result-20181211_7872576736.png
breitbandmessung.de mit Bonding:
Screenshot from 2018-12-11 23-56-41.png
Also ein voller Erfolg. Das Ergebnis von breitbandmessung trifft es auch recht genau: Aus 1060Mbit/s Ethernet-Brutto (inkl. FCS) ergeben sich rechnerisch 1060 * 1460/1518 = 1019,499Mbit/s TCP/IPv4-Netto.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

robert_s
Insider
Beiträge: 3526
Registriert: 30.11.2010, 15:09

Re: Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Beitrag von robert_s » 23.12.2018, 23:22

Flole hat geschrieben:
12.12.2018, 02:23
Modus 6 wäre es gewesen, und den hast du im Prinzip nachgebaut (nur schlechter):
Ich habe es jetzt mit Modus 0 hinbekommen, das geht in Ubuntu 16.04 sogar über die GUI - allerdings nur, wenn man es richtig macht, und die GUI zeigt es dann auch nicht richtig an.

Ubuntu 16.04 LTS (Englisch):

1. In der Taskleiste auf das Netzwerksymbol klicken und im Menü den untersten Punkt "Edit Connections" anwählen.
2. Links in der Liste die beiden Ethernet-Verbindungen, die gebündelt werden sollen, jeweils anklicken und LÖSCHEN (rechts auf "Delete" klicken) - WICHTIG, sonst funktioniert es nicht!
3. Rechts auf "Add" klicken, Type "Bond" auswählen und "Create..." klicken.
4. Unter "Bonded connections" auf "Add" klicken, "Ethernet" gewählt lassen und "Create..." klicken. Damit erzeugt man eine NEUE Ethernet-Verbindung (deshalb mussten die alten gelöscht werden, weil die sonst weiter ohne Bündelung gelaufen wären - eine Übernahme von bestehenden Ethernet-Verbindungen scheint an dieser Stelle nicht möglich). Unter "Device" wählt man eines der Netzwerkinterfaces, das gebündelt werden soll, aus und klickt dann "Save".
5. Schritt 4 für das zweite zu bündelnde Netzwerkinterface wiederholen.
6. Eventuell noch "Link up delay" auf 100 ms stellen. Zumindest hatte ich bei mir plötzlich das Problem, dass eins der Netzwerkinterfaces nur noch mit 100Mbit/s lief. Ich bin mir noch nicht sicher, ob das mit dieser Einstellung vollständig gelöst ist.
7. Alle anderen Einstellungen kann man auf den Voreinstellungen lassen.
8. Danach auf "Save" klicken um die gebündelte Verbindung zu speichern.
9. Nun den Rechner neustarten (anders kam die gebündelte Verbindung bei mir nicht hoch).

Im Drop-Down Menü unter dem Netzwerksymbol werden danach die beiden einzelnen Verbindungen als "Auto Ethernet" angezeigt und die Bündelung gar nicht. Aber unter "Connection Information" sieht man die gebündelte Verbindung und die beiden gebündelten Netzwerkinterfaces.

Alternativ kann man auch in der Shell mit "nmcli c" den Status anschauen. Dabei sollte die gebündelte Verbindung sowie die dazugehörigen Einzelverbindungen in grün angezeigt werden. Hat man anfangs die bestehenden Ethernet-Verbindungen nicht gelöscht, sind die stattdessen grün und die zu bündelnden Verbindungen gelb - und werden eben nicht gebündelt.


Wie das nun zu funktionieren scheint:

Die gebündelte Verbindung übernimmt nur die MAC-Adresse eines der beiden Netzwerkinterfaces (wohl dessen, das zuerst hochkommt) und holt sich damit eine IPv4-Adresse. Die MAC-Addresse des jeweils anderen Netzwerkinterfaces wird überhaupt nicht benutzt, sondern darauf die gleiche MAC-Adresse "geklont". Durch abwechselndes Senden auf den beiden Netzwerkinterfaces wird wohl die MAC-Tabelle im Switch ständig verändert, sodass der, wenn er einen Ethernet-Frame an die eine MAC-Adresse zu senden hat, jeweils den einen oder den anderen Port nimmt.

Klingt ja an sich wie echtes Layer-2 Balancing, d.h. selbst ein einzelner TCP-Stream sollte doch so auf beide Verbindungen verteilt werden können - wird aber nicht :(

Die Frage ist auch, ob ein Managed Switch sich das gefallen lassen würde. Aber da es in Kabelroutern eh keinen gibt, ist das auch ziemlich egal.

Kretzian
Newbie
Beiträge: 45
Registriert: 28.04.2019, 15:53

Re: Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Beitrag von Kretzian » 25.05.2019, 21:17

Hallöle,

mal für dummen auf dem Gebiet: Geht das auch mit Windows, falls ja - gibt es dazu ebenfalls eine Anleitung?

Liebe Grüße

robert_s
Insider
Beiträge: 3526
Registriert: 30.11.2010, 15:09

Re: Load Balancing mit Ubuntu/Linux: Gigabit-Anschluss ausreizen

Beitrag von robert_s » 09.11.2019, 09:51

robert_s hat geschrieben:
23.12.2018, 23:22
Die Frage ist auch, ob ein Managed Switch sich das gefallen lassen würde. Aber da es in Kabelroutern eh keinen gibt, ist das auch ziemlich egal.
Das scheint übrigens nicht zu stimmen, der Switch in der 6591 ist wohl doch kein "dummer"...