Freifunk-Gateway aufsetzen/Batman-Gatewayselection

= B.A.T.M.A.N Gateway Selection =
== Funktion & Konfiguration ==
Mit der BATMAN Gateway Selection werden DHCP Anfragen die eigentlich Multicasts sind in Unicast zu einzelnen Gateways auf den Knoten umgewandelt. Damit der Knoten weiß, welche DHCP Server im Netz sind, muss man als DHCP Server sich mit einer Bandbreite announcen. Anhand der announcend Bandbreite und der Metrik des Gateways wird nun entschieden welches Gateway ausgewählt wird.
Es kann z.b. eine feste Bandbreite announced werden (siehe Freifunk-Gateway_aufsetzen/Batman-adv#IPv4
batctl -m bat-nuernberg gw_mode server 100mbit
oder ein Script verwendet werden, das die Bandbreite dynamisch anhand der Auslastung berechnet:
== Gateway Selection dynamisch festlegen ==
Achtung: Das dynamische Verändern der Gateway Selection macht das Debugging noch wesentlich komplizierter, als es eh schon ist. Bei den meisten Aufbauten bringt das auch gar nichts.
Daher ist es (vor allem für den Anfang) NICHT empfehlenswert, etwas derartiges einzurichten.
ACHTUNG: Diese Schritte sollte erst aktiviert werden wenn sicher feststeht das:
* Babel alle Routen übertragen hat, "ip r s table fff" gibt viele routen zu 10.x.x.x und 172.x.x.x aus
* Ein funktionierender DHCP Server läuft
Wird das announcen vorher aktiviert, announced man sich im Batman als Gateway obwohl man keine IPs vergibt (oder nicht richtig routet). Dies führt dazu das Clients keine IPs oder kein Routing ins Freifunknetz bekommen was sehr unschön ist.
Ab Version 0.5.1 der Router Firmware ist die B.A.T.M.A.N Gateway Selection aktiviert worden. Der Router wählt sein bevorzugtes Gateway anhand der Verbindungsqualität und dessen noch verfügbaren Bandbreite aus und selektiert das GW für die Clients vor.
Die noch verfügbare Bandbreite muss vom Gateway an die Router annonciert werden. Hierfür muss man vorab die maximal zur Verfügung stehende Up- und Downloadkapazität des Gateways festlegen. Dies kann z.B. unter folgenden Gesichtspunkten geschehen:
* Bandbreite der Netzanbindung (z.B. 100 Mbit/sec, gesplittet in 50 Mbit/sec up/down)
* Freier Traffic des Hosters (z.B.: 5 TByte/Monat, entspricht einer Grundlast von 15 Mbit/sec, z.B. gesplittet in 5 Mbit/sec down, 10 Mbit/sec up)
* Erfahrungswerten / eigenes Ermessen
* Bandbreite, bei dem der Gateway Prozessor ausgelastet ist
Eventuell muss zuerst bc nachinstalliert werden, falls nicht vorhanden:
apt-get install bc
Wir sollten nur die Bandbreite annoncieren, die tatsächlich noch frei ist: Also unsere Gesamtkapazität abzüglich der verwendeten Bandbreite. Hierfür kann man ein Skript verwenden, dass die aktuell verwendete (zeitlich gemittelte) Bandbreite vom Gateway ausliest, mit der Gesamtkapazität vergleicht und die noch freie Bandbreite an die GW Selection weitergibt.
Importieren des Skripts aus einer Vorlage:
wget https://raw.githubusercontent.com/FreifunkFranken/configs/master/dyn_announce_gw_bw.sh -P /usr/local/bin/
Alternativ kann das Skript auch als leere Datei erstellt werden:
touch /usr/local/bin/dyn_announce_gw_bw.sh
Wir machen das Skript ausführbar und öffnen die Datei:
chmod +x /usr/local/bin/dyn_announce_gw_bw.sh
vi /usr/local/bin/dyn_announce_gw_bw.sh
Und Füllen dieses mit Inhalt oder editieren den importierten Inhalt:
#!/bin/bash
gwsel_lockfile="/tmp/gwsel_lockfile" # lockfile to allow for low bandwidth settings 
if [ -z "$1" ]; then
 echo
 echo "usage: $0 <network-interface> <update_interval [sec]> <total BW up [Mbit/sec]> <total BW down [Mbit/sec]>"
 echo
 echo "e.g. $0 eth0 60 10 10"
 echo
 exit
fi
while true
do
 if [ ! -e ${gwsel_lockfile} ]; then # lockfile not present
 # Bandwidth currently used (time averaged)
 R1=$(cat "/sys/class/net/$1/statistics/rx_bytes")
 T1=$(cat "/sys/class/net/$1/statistics/tx_bytes")
 sleep "$2"
 R2=$(cat "/sys/class/net/$1/statistics/rx_bytes")
 T2=$(cat "/sys/class/net/$1/statistics/tx_bytes")
 TkbitPS=$(echo "scale=0; ($T2 - $T1) / 1024 * 8 / $2" | bc -l)
 RkbitPS=$(echo "scale=0; ($R2 - $R1) / 1024 * 8 / $2" | bc -l)
# echo "BW used -- up $1: $TkbitPS kBit/s; down $1: $RkbitPS kBit/s"
 # Remaining bandwidth available; cut-off negative values
 Tavail_kbitPS=$(echo "scale=0; if (($3 * 1024 - $TkbitPS) >0) ($3 * 1024 - $TkbitPS) else 0" | bc -l)
 Ravail_kbitPS=$(echo "scale=0; if (($4 * 1024 - $RkbitPS) >0) ($4 * 1024 - $RkbitPS) else 0" | bc -l)
# echo "BW available -- up $1: $Tavail_kbitPS kBit/s; down $1: $Ravail_kbitPS kBit/s"
 else # lockfile present
 Tavail_kbitPS=0
 Ravail_kbitPS=0
 sleep "$2"
 fi
 if [ `pidof dhcpd` != "" ]; then
 for bat in /sys/class/net/bat*; do
 iface=${bat##*/}
 batctl -m $iface gw_mode server "${Ravail_kbitPS}kbit/${Tavail_kbitPS}kbit"
 done
 else
 for bat in /sys/class/net/bat*; do
 iface=${bat##*/}
 batctl -m $iface gw_mode off
 done
 rm /var/run/dhcpd.pid >/dev/null 2>&1
 /etc/init.d/isc-dhcp-server restart
 fi
done
Achtung:
Wenn man ein bat Interface hat, das nicht Gateway ist muss man dies aus der letzten Schleife ausschließen da sonst dort ebenfalls die Gatewayselection aktiviert wird und man eine Bandbreite announced.
Das Skript übernimmt als Parameter:
* Netzwerkinterface, das es zu überwachen gilt (i.d.R. eth0)
* Updateintervall in Sekunden, in denen ein neuer Wert durch die B.A.T.M.A.N GW Selection annonciert wird (Um nicht allzu volatil auf Kurzzeitschwankungen im Durchsatz zu reagieren empfiehlt sich ein Mittelungsintervall zwischen 30 und 120 Sekunden)
* Upload Kapazität in Mbit/sec (insgesamt zur Verfügung stehend s.o.)
* Download Kapazität in Mbit/sec (insgesamt zur Verfügung stehend s.o.)
Bei Existenz des oben definierten Lockfiles "/tmp/gwsel_lockfile", annonciert das Gateway nur noch eine minimale Bandbreite. Dies dient dazu, möglichst keine neuen Clients zu akquirieren, z.B. weil gerade der VPN Tunnel ausgefallen ist und nur noch eine Babel Defaultroute mit geringer Bandbreite verfügbar ist.
Ein Aufruf für eth0 als Interface, ein Update alle 5 Minuten, 12 Mbit/sec maximaler Upload und 10 Mbit/sec maximaler Download wäre z.B.:
/usr/local/bin/dyn_announce_gw_bw.sh eth0 300 12 10
Bei Debian 9 muss das Interface angepasst werden.
Als Beispiel:
/usr/local/bin/dyn_announce_gw_bw.sh ens18 300 12 10
Um die Gateway Selection beim Systemsstart zu aktivieren, können wir das Skript z.B. in rc.local aufrufen:
vi /etc/rc.local
um dort, leicht zeitverzögert, o.a. Befehl einzupflegen, wobei die Parametrisierung noch Gateway-spezifisch angepasst werden muss:
.
.
.
#enable batman GW selection with 15 seconds delay
(sleep 15; /usr/local/bin/dyn_announce_gw_bw.sh eth0 300 12 10) &
.
.
.
auf den Routern kann der vorselektierte Gateway mit 
batctl gwl
 
angeguckt werden.
== Gatewayselection abschalten wenn Lease voll ==
Wenn man keine DHCP Leases mehr zur Verfügung hat, sollte die Gateway Selection abgeschaltet werden, damit Clients die DHCP-Offers des anderen Gateways sehen können. Dazu muss ein passendes Skript gebaut werden, dass die Anzahl der Leases prüft.
Das Skript muss dann natürlich regelmäßig aufgerufen werden, z.B. per Cron.
Unten ist dafür ein Beispiel, wie so ein Skript aussehen könnte.
# Vergebene Leases beim isc-dhcp-server zählen
#leasecount=$(/usr/sbin/dhcp-lease-list --parsable --lease /var/lib/dhcp/dhcpd.leases 2>&1 | grep "10.50.6" | wc -l)
# Vergebene Leases beim dnsmasq zählen
leasecount=$(cat /var/lib/misc/nuernberg.leases | wc -l)
# Bei entsprechender Anzahl an vergebenen Leases (-gt => greater than) die Selection entsprechend anpassen
if [ $leasecount -gt 450 ]; then 
	/usr/local/sbin/batctl -m bat4 gw_mode off
else
	/usr/local/sbin/batctl -m bat4 gw_mode server 5mbit/5mbit
fi