Offloader auf Basis eines Raspberry PI 4B (FASTD)
Achtung diese Anleitung ist veraltet und funktioniert nicht mehr mit Freifunk München! Bitte verwendet die Wireguard Anleitung
Disclaimer: Die Anleitung ist nur für Leute, die sich bereits mit dem Thema Linux auseinander gesetzt haben oder sich intensiv damit beschäftigen wollen.
Diese Anleitung funktioniert auf quasi allen Linux basierten Betriebssystemen, mit ein paar Anpassungen.
Mit dem Raspberry PI 4 ist es das erste Mal möglich, einen Offloader sinnvoll auf einem PI zu betreiben. Denn in dieser Version bietet der Ethernet Anschluss genug Durchsatz und die CPU ist leistungsfähig genug um eine ordentliche fastd Performance zu bieten. Dies ist bei den Vorgänger Modellen leider nicht der Fall.
Für kabelgebundene Clients und/oder Meshing per Kabel benötigt ihr einen VLAN-fähigen Switch!
Angeboten wird das PI in einer 1GB, 2GB und 4GB RAM Variante. Will man wirklich nur einen reinen Offloader ohne Zusatzfunktionen betreiben, reicht im Grunde die 1GB Version. Allerdings ist mehr RAM immer besser ;) und man weiß ja nicht, was man im Endeffekt noch alles darauf betreiben will.
Nachdem es kein fertiges Gluon Image für das Raspberry PI 4B gibt im Moment, installieren wir erstmal strikt nach Anleitung das aktuelle Raspbian.
Außerdem ermöglicht uns der Einsatz von Raspbian, dass wir alle normalen Anwendungen wie Webserver, Chatserver oder den Unifi-Controller einfach installieren können.
Auf dem FFBSeeCamp 2019 gab es auch einen Vortrag zum Thema.
Vom CCC gibt es dazu auch einen recent audio-only feed Raspberry PI4 als Offloader (tc19).
Eine Anleitung dazu findet ihr auf der offiziellen Raspbian Seite.
Am Ende der Prozedur, empfiehlt es sich auf der Boot Partition einfach eine leere Datei mit dem Namen „ssh“ anzulegen. Das aktiviert den SSH Daemon und man kann bequem per Putty, OpenSSH oder sonstigen Clients remote auf das PI zugreifen.
Der Benutzername lautet „pi“ und das Passwort „raspberry“. Unbedingt ändern! Sonst kommen Leute aus dem Internet auf euer Raspberry!
Möchte man vom Raspberry später auch ein WLAN ausstrahlen lassen so ist es zwingend von Nöten, dass WIFI explizit via rfkill freizugeben! Hier loggen wir uns per SSH ein und setzen folgenden Befehl ab:
# rfkill unblock wifi
Anschließend starten wir den Raspberry 1x neu!
# systemctl reboot
Ansible-Playbook gesteuerter Bau des Offloaders
Wer nicht die nachfolgenden gut dokumentierten Schritte per Hand ausführen möchte, kann sich auch mit Hilfe von Ansible binnen 20 Minuten automatisiert einen Offloader Menügeführt und scriptiert erstellen lassen.
Das entsprechende HOWTO findet man in Djangos WIKI.
BATMAN
Nachdem ihr euch eingeloggt habt, wechseln wir zum Root User und laden das BATMAN Kernelmodul herunter. Das wird gebraucht um nachher das Routing innerhalb des Freifunknetzes zu übernehmen.
Am Besten schaut ihr vorher, welches die aktuelle BATMAN Version ist.
pi@raspberrypi:~ $ sudo su - root@raspberrypi:~# cd /usr/src/ root@raspberrypi:/usr/src# wget https://downloads.open-mesh.org/batman/releases/batman-adv-2019.2/batman-adv-2019.2.tar.gz root@raspberrypi:/usr/src# tar xzf batman-adv-2019.2.tar.gz
Nachdem das Kernelmodul manuell gebaut wird, wollen wir natürlich dass das auch Bestand hat, wenn ein Kernelupdate eingespielt wird. Dazu brauchen wir nun einige Pakete.
root@raspberrypi:/usr/src# apt update && apt install dkms raspberrypi-kernel-headers
Anschließend müssen wir auf Grund dessen, dass der Raspberry PI Kernel crosscompiled wurde die make Skripte neu generieren.
root@raspberrypi:/usr/src# cd linux-headers-$(uname -r) root@raspberrypi:/usr/src/linux-headers-4.19.50-v7l+# make scripts
Es kann passieren, dass hier nach einiger Zeit mit der Fehlermeldung
„scripts/sortextable.c:31:10: fatal error: tools/be_byteshift.h: No such file or directory“
abgebrochen wird, das stellt aber kein Problem dar.
Nun nachdem die Vorbereitungen getroffen sind, zurück zu BATMAN. Und dem Anlegen der dkms.conf.
root@raspberrypi:/usr/src/linux-headers-4.19.50-v7l+# cd ../batman-adv-2019.2/ root@raspberrypi:/usr/src/batman-adv-2019.2# vi dkms.conf
Der Inhalt der dkms.conf sieht wie folgt aus:
PACKAGE_NAME=batman-adv PACKAGE_VERSION=2019.2 DEST_MODULE_LOCATION=/extra BUILT_MODULE_NAME=batman-adv BUILT_MODULE_LOCATION=net/batman-adv MAKE="'make'" CLEAN="'make' clean" AUTOINSTALL="yes"
Die Datei speichern und schon sind wir bereit für das erste Mal bauen des Kernelmodules.
root@raspberrypi:/usr/src/batman-adv-2019.2# dkms add -m batman-adv -v 2019.2 root@raspberrypi:/usr/src/batman-adv-2019.2# dkms build -m batman-adv -v 2019.2 root@raspberrypi:/usr/src/batman-adv-2019.2# dkms install -m batman-adv -v 2019.2
Als nächstes müssen wir dafür sorgen, dass das Kernelmodul beim Boot auch geladen wird. Dazu müssen wir die Datei „/etc/modules-load.d/batman-adv.module.conf“ wie folgt anpassen.
root@raspberrypi:/usr/src/batman-adv-2019.2# vi /etc/modules-load.d/batman-adv.module.conf
# # Load batman-adv module on system boot # batman-adv dummy
Nun kann man entweder rebooten oder die Module manuell laden.
root@raspberrypi:/usr/src/batman-adv-2019.2# modprobe dummy root@raspberrypi:/usr/src/batman-adv-2019.2# modprobe batman_adv
Um BATMAN verwalten zu können müssen wir nun noch „batctl“ installieren.
root@raspberrypi:/usr/src/batman-adv-2019.2# apt install batctl
Dann überprüfen wir ob alles korrekt geladen ist.
root@raspberrypi:/usr/src/batman-adv-2019.2# batctl ra
Active routing protocol configuration: Selected routing algorithm (used when next batX interface is created): => BATMAN_IV Available routing algorithms: * BATMAN_IV * BATMAN_V
Nachdem wir BATMAN_V bei uns verwenden, sehen wir dass aktuell der falsche Routing Algorithmus ausgewählt ist. Das korrigieren einmal sofort manuell.
root@raspberrypi:/usr/src/batman-adv-2019.2# batctl ra BATMAN_V
Nun kommen wir zur Interface Konfiguration. In diesem Beispiel, werden wir das Raspberry PI im Segment „welt“ ansiedeln, deswegen heißen auch die Interfaces entsprechend.
root@raspberrypi:/usr/src/batman-adv-2019.2# apt install bridge-utils
- /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8) # Please note that this file is written to be used with dhcpcd # For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf' # Include files from /etc/network/interfaces.d: auto eth0 iface eth0 inet dhcp auto br-welt iface br-welt inet dhcp bridge-ports bat-welt pre-up /usr/sbin/batctl ra BATMAN_V pre-up /sbin/ip link add dummy-welt type dummy pre-up /sbin/ip link set address $(ip -br l | grep eth0 | egrep -o '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' | head -1) dev dummy-welt pre-up /sbin/ip link set dummy-welt up pre-up /usr/sbin/batctl -m bat-welt if add dummy-welt pre-up /sbin/ip link set bat-welt up pre-up /usr/sbin/batctl -m bat-welt gw_mode client pre-up /sbin/ip link set address $(ip -br l | grep eth0 | egrep -o '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' | head -1) dev bat-welt post-up /sbin/ip link set address $(ip -br l | grep eth0 | egrep -o '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' | head -1) dev br-welt
Im Beispiel setzen wir die MAC Addresse für BATMAN fest auf die MAC von eth0, damit wir später auch Statistiken etc abrufen können.
FASTD
Bitte informiert euch vorher in welches Segment ihr wollt, dementsprechend muss der FASTD Port angepasst werden!
Domain | FASTD Port |
---|---|
ffmuc_muc_cty | 30002 |
ffmuc_muc_nord | 30003 |
ffmuc_muc_ost | 30004 |
ffmuc_muc_sued | 30005 |
ffmuc_muc_west | 30006 |
ffmuc_uml_nord | 30007 |
ffmuc_uml_ost | 30008 |
ffmuc_uml_sued | 30009 |
ffmuc_uml_west | 30010 |
ffmuc_gauting | 30012 |
ffmuc_freising | 30013 |
ffmuc_welt | 30011 |
Um zum Freifunk München Netz verbinden zu können, brauchen wir nun noch fastd.
Diesen installieren wir einfach per apt
root@raspberrypi:~# apt install fastd
Und anschließend generieren wir uns einen Key, den wir zum Verbinden und verschlüsseln benötigen.
root@raspberrypi:~# fastd --generate-key
2019-07-05 10:57:41 +0100 --- Info: Reading 32 bytes from /dev/random... Secret: 1843fd17494d265d65f9563e3655728dbf1c8f7fb04365a9ab733f4debdb8f51 Public: 7703d5f1766c11cc701cc039af1913faef216ced7b33dd18f87e57c172e0324e
Wir benötigen davon nur den Secret Key. Anschließend erzeugen wir die Konfiguration.
root@raspberrypi:~# mkdir /etc/fastd/welt root@raspberrypi:~# vi /etc/fastd/welt/fastd.conf
# vi /etc/fastd/welt/fastd.conf
- /etc/fastd/welt/fastd.conf
# # welt FASTd configuration # log to syslog level info; interface "fastd-welt"; method "salsa2012+umac"; method "null"; secret "1843fd17494d265d65f9563e3655728dbf1c8f7fb04365a9ab733f4debdb8f51"; mtu 1406; status socket "/var/run/fastd.welt.sock"; on up " batctl ra BATMAN_V ip link set $INTERFACE down ip link set address $(ip -br l | grep eth0 | egrep -o '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' | head -1) dev $INTERFACE ip link set $INTERFACE up batctl -m bat-welt if add $INTERFACE "; on down " batctl -m bat-welt if del $INTERFACE "; peer group "ffmuc" { peer limit 1; peer "gw04.in.ffmuc.net" { key "179c91d4b3b6676d032b622809bbdfa563c70f8873fb2b8c1e62d61020acd550"; remote "gw04.ext.ffmuc.net" port <Port siehe oben - z.B. 30004>; } peer "gw05.in.ffmuc.net" { key "f26f70fea16e0708c1899ac373b24881b16b9cbfba9d24703617e98a260abb72"; remote "gw05.ext.ffmuc.net" port <Port siehe oben - z.B. 30004>; } }
Nun aktivieren wir „fastd“ für den Boot.
root@raspberrypi:~# systemctl enable fastd@welt
ext-respondd
Dieser Teil ist wichtig, da es sein kann dass ihr gegen die Nutzungsbedingungen einiger Communities verstoßt, wenn ihr euch nicht als Knoten im Netz meldet. Außerdem trägt es generell zur Netzhygiene bei, wenn alle Knoten in den Statistiken auftauchen.
Nachdem wir auch auf der Knotenkarte auftauchen wollen, installieren wir auch noch ext-respondd
root@raspberrypi:~# apt install git python3-netifaces root@raspberrypi:~# git clone https://github.com/freifunkMUC/ext-respondd /opt/ext-respondd/ root@raspberrypi:~# cp /opt/ext-respondd/ext-respondd.service.example /etc/systemd/system/ext-respondd.service root@raspberrypi:~# systemctl daemon-reload root@raspberrypi:~# systemctl enable ext-respondd
Dann müssen wir auch noch die Konfigurationsdateien von ext-respondd anpassen.
Bitte tragt die Daten inklusive dem Segmentnamen korrekt ein. Eine Übersicht der Segmentnamen gibt es hier.
root@raspberrypi:~# vi /opt/ext-respondd/alias.json
Die Dateien sind selbsterklärend, einfach die nötigen Infos eintragen.
{ "nodeinfo": { "hostname": "aw-raspi-4", "hardware": { "model": "Raspberry Pi 4B" }, "owner": { "contact": "awlnx @ chat.ffmuc.net" }, "system": { "site_code": "<segmentname>", "role": "client" } }, "firstseen": "2015-04-12T15:41:01" }
root@raspberrypi:~# vi /opt/ext-respondd/config.json
{ "batman": "bat-welt", "bridge": "br-welt", "mesh-vpn": [ "fastd-welt" ], "wan": "eth0", "rate_limit": 30, "rate_limit_burst": 10 }
Checken der Konfiguration
Anschließend rebooten wir einmal und wenn alles stimmt sollte der Knoten auf der Karte erscheinen und „batctl“ folgendes liefern, der Neighbor kann je nach GW ein anderer sein:
root@raspberrypi:~# batctl -m bat-welt n [B.A.T.M.A.N. adv 2019.1, MainIF/MAC: dummy-welt/dc:a6:32:00:6b:59 (bat-welt/86:6e:aa:be:bb:94 BATMAN_V)] IF Neighbor last-seen f2:00:22:10:00:00 0.060s ( 1.0) [fastd-welt]
Nun sollet ihr eine IPv6 Adresse aus dem gewählten Segment auf eurem Interface sehen.
root@raspberrypi:~# ip -br a | grep br-welt br-welt UP 10.80.203.128/21 2001:608:a01:109:dea6:32ff:fe00:6b59/64 fe80::dea6:32ff:fe00:6b59/64
Meshing per Kabel
Falls ihr per Kabel meshen wollt, ist dies nur sinnvoll per VLAN möglich.
Dazu müsst ihr zuerst ein VLAN Interface in /etc/network/interfaces anlegen und dieses an das BATMAN Interface hängen.
- /etc/network/interfaces
auto eth0.666 iface eth0.666 inet manual post-up /usr/sbin/batctl ra BATMAN_V post-up /usr/sbin/batctl -m bat-welt if add eth0.666
Beachtet bitte, das Setup funktioniert nur in Umgebungen ohne VXLAN Meshing. Mit VXLAN Meshing braucht es auch noch ein VXLAN Interface.
Mehr dazu siehe unten.
Mesh per vxlan
Für andere Communities benötigt ihr die entsprechenden VXLAN IDs zum Meshen
Um meshing per Kabel nutzen zu können, muss bei manchen Communities (wie bei FFMUC) VXLAN benutzt werden.
Bei uns gibt es momentan folgende VXLAN IDs, diese werden von GLUON dynamisch aus dem domain_seed erzeugt.
Domain | vxlan id |
---|---|
ffmuc_muc_cty | 10758607 |
ffmuc_muc_nord | 15521492 |
ffmuc_muc_ost | 2948862 |
ffmuc_muc_sued | 8599288 |
ffmuc_muc_west | 7318933 |
ffmuc_uml_nord | 5705961 |
ffmuc_uml_ost | 4892713 |
ffmuc_uml_sued | 16544703 |
ffmuc_uml_west | 16677749 |
ffmuc_gauting | 16175732 |
ffmuc_freising | 12937858 |
ffmuc_welt | 16306234 |
Um die VXLAN ID aus einem domain_seed zu berechnen haben wir ein kleines Python Skript geschrieben.
python3 get_vxlan_id_from_domain_seed.py domain_seed
Die Konfiguration in /etc/network/interfaces sieht so aus, um per VLAN666 VXLAN Meshing für das Segment Welt zu machen. Wie ihr seht, wird dafür die ID aus der obigen Tabelle benötigt.
- /etc/network/interfaces
auto eth0.666 iface eth0.666 inet manual pre-up /sbin/ip link add vxlan-mesh type vxlan id 16306234 group ff02::15c dstport 4789 port 32768 61000 no udpcsum udp6zerocsumtx udp6zerocsumrx dev eth0.666 || true up /sbin/ip link set vxlan-mesh up post-up /usr/sbin/batctl ra BATMAN_V post-up /usr/sbin/batctl -m bat-welt if add vxlan-mesh down ip link set vxlan-mesh down post-down ip link del vxlan-mesh || true
Damit das vxlan-mesh Interface auch der bevorzugte Meshingpoint in BATMAN_V wird noch folgendes in die /etc/rc.local hinzufügen.
- /etc/rc.local
echo 1000000 > /sys/devices/virtual/net/vxlan-mesh/batman_adv/throughput_override
Danach rebooten oder das Interface hochfahren. Wenn alles geklappt hat und ihr bereits einen Router zum Meshen in diesem VLAN habt, sollte danach folgendes in batctl zu sehen sein.
root@raspberrypi:~# batctl -m bat-welt n [B.A.T.M.A.N. adv 2018.3, MainIF/MAC: vxlan-mesh/4a:af:0b:bf:44:0c (bat-welt/dc:a6:32:00:6b:59 BATMAN_V)] IF Neighbor last-seen 52:98:0e:9b:5f:9c 0.470s ( 1.0) [vxlan-mesh] f2:00:22:10:00:00 0.420s ( 1.0) [fastd-welt]
Sollte sich kein Client am Mesh VLAN befinden, wird die vxlan-mesh Zeile nicht angezeigt.
Außerdem sollten die Interfaces wie folgt aussehen:
root@ffoff:~# batctl -m bat-welt if dummy-welt: active vxlan-mesh: active fastd-welt: active
Leider ist der Link zum Gateway auf der Map nicht zu sehen.
Wifi Clients
Dazu müssen wir hostapd installieren und konfigurieren; bei der Vergabe der SSID ist zu beachten:
WICHTIG: Das Abändern der zum Segment passenden SSID ist gemäß der Nutzungsbedingungen nicht gestattet!
- 5. Lokale Zusätze für Freifunk München
Das Betreiben von Routern in Verbindung mit der Freifunk-München Netzwerkinfrastruktur ist nur gestattet, solange die folgenden zwei Bedingungen erfüllt sind:- die SSID des Client-Netzes auf “muenchen.freifunk.net/(Segmentname)” lautet
- die Mesh-BSSID/SSID denen, der in den offiziellen Firmware-Images veröffentlichten, entspricht
Die Liste der SSIDs findet ihr hier:
Aktuell1) gibt es folgende Segmente:
SSID | Segment-Name | IPv4-Prefix | IPv6-Prefix Wien | IPv6-Prefix München |
---|---|---|---|---|
muenchen.freifunk.net/muc_cty | ffmuc_muc_cty | 10.80.128.0/21 | 2001:678:e68:100::/64 | 2001:678:ed0:100::/64 |
muenchen.freifunk.net/muc_nord | ffmuc_muc_nord | 10.80.136.0/21 | 2001:678:e68:101::/64 | 2001:678:ed0:101::/64 |
muenchen.freifunk.net/muc_ost | ffmuc_muc_ost | 10.80.144.0/21 | 2001:678:e68:102::/64 | 2001:678:ed0:102::/64 |
muenchen.freifunk.net/muc_sued | ffmuc_muc_sued | 10.80.152.0/21 | 2001:678:e68:103::/64 | 2001:678:ed0:103::/64 |
muenchen.freifunk.net/muc_west | ffmuc_muc_west | 10.80.160.0/21 | 2001:678:e68:104::/64 | 2001:678:ed0:104::/64 |
muenchen.freifunk.net/uml_nord | ffmuc_uml_nord | 10.80.168.0/21 | 2001:678:e68:105::/64 | 2001:678:ed0:105::/64 |
muenchen.freifunk.net/uml_ost | ffmuc_uml_ost | 10.80.176.0/21 | 2001:678:e68:106::/64 | 2001:678:ed0:106::/64 |
muenchen.freifunk.net/uml_sued | ffmuc_uml_sued | 10.80.184.0/21 | 2001:678:e68:107::/64 | 2001:678:ed0:107::/64 |
muenchen.freifunk.net/uml_west | ffmuc_uml_west | 10.80.192.0/21 | 2001:678:e68:108::/64 | 2001:678:ed0:108::/64 |
muenchen.freifunk.net/welt | ffmuc_welt | 10.80.200.0/21 | 2001:678:e68:109::/64 | 2001:678:ed0:109::/64 |
muenchen.freifunk.net/gauting | ffmuc_gauting | 10.80.208.0/21 | 2001:678:e68:10a::/64 | 2001:678:ed0:10a::/64 |
muenchen.freifunk.net/freising | ffmuc_freising | 10.80.216.0/21 | 2001:678:e68:10b::/64 | 2001:678:ed0:10b::/64 |
muenchen.freifunk.net/augsburg | ffmuc_augsburg | 10.80.224.0/21 | 2001:678:e68:10c::/64 | 2001:678:ed0:10c::/64 |
root@raspberrypi:~# apt install hostapd root@raspberrypi:~# echo 'DAEMON_OPTS="-d"' >> /etc/default/hostapd root@raspberrypi:~# vi /etc/hostapd/hostapd.conf
vi /etc/hostapd/hostapd.conf
- /etc/hostapd/hostapd.conf
ssid=muenchen.freifunk.net/welt country_code=DE interface=wlan0 driver=nl80211 macaddr_acl=0 logger_syslog=0 logger_syslog_level=4 logger_stdout=-1 logger_stdout_level=0 hw_mode=a wmm_enabled=1 # N ieee80211n=1 require_ht=1 ht_capab=[MAX-AMSDU-3839][HT40+][SHORT-GI-20][SHORT-GI-40][DSSS_CCK-40] # AC ieee80211ac=1 require_vht=1 ieee80211d=0 ieee80211h=0 vht_capab=[MAX-AMSDU-3839][SHORT-GI-80] vht_oper_chwidth=1 channel=36 vht_oper_centr_freq_seg0_idx=42
Danach hostapd für den Systemstart aktivieren und starten.
root@raspberrypi:~# systemctl unmask hostapd root@raspberrypi:~# systemctl enable hostapd root@raspberrypi:~# systemctl start hostapd
Das Wlan0 muss nun noch in die Bridge gepackt werden. Dazu passen wir die /etc/rc.local an.
#!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. # Print the IP address _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi sleep 10; /sbin/brctl addif br-welt wlan0 exit 0
Am Besten nochmal rebooten um sicher zugehen dass alles passt, danach einfach mit dem ClientWifi verbinden.
LAN Clients
Diese sind im Grunde ganz einfach, ihr erstellt ein VLAN Interface in der /etc/network/interfaces. Und verbindet dieses mit der Bridge, schon könnt ihr per getaggtem VLAN euer Clientnetz bereitstellen.
Hier ein Beispiel mit VLAN333, erst das VLAN Interface definieren und dann in der vorhandenen Bridge hinzufügen.
vi /etc/network/interfaces
- /etc/network/interfaces
auto eth0.333 iface eth0.333 inet manual auto br-welt iface br-welt inet dhcp bridge-ports bat-welt eth0.333
Geschwindigkeiten
Nun zur wichtigsten Frage, welche Performance kann man erwarten.
Hier ein paar Speedtest Ergebnisse:
$ wget -O /dev/null https://speed.hetzner.de/10GB.bin --report-speed=bits
--2019-07-01 09:12:45-- https://speed.hetzner.de/10GB.bin Resolving speed.hetzner.de (speed.hetzner.de)... 88.198.248.254 Connecting to speed.hetzner.de (speed.hetzner.de)|88.198.248.254|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 10485760000 (9.8G) [application/octet-stream] Saving to: ‘/dev/null’ /dev/null 2%[===> ] 288.96M 115Mb/s eta 14m 34s
Ändern des Hostnamen
Hat man mehr als einen Raspberry in seinem Netzwerk am laufen, so kann es mitunter sehr schnell unübersichtlich werden, wenn alle Geräte den gleichen Hostnamen verwenden und z.B. mit diesen an einem zentralen DHCP-Server melden und eine IP-Adresse beziehen. Wir wollen daher den Hostnamen auf den wer setzen, den wir für unseren Offloader beim Setzen des Nodenamen zuvor bei der Definition des ext-respondd beim Parameter site_code
gesetzt hatten. In nachfolgendem Konfigurationsbeispiel verwenden wir mal den Site_code/Hostname ff-django-raspi.
pi@raspberrypi:~ $ sudo su - root@raspberrypi:~# hostnamectl set-hostname ff-django-raspi root@raspberrypi:~# vi /etc/hosts
127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters 127.0.1.1 ff-django-raspi
root@raspberrypi:~# hostnamectl
Static hostname: ff-django-raspi Icon name: computer Machine ID: b08567d7855541cf8110f09e88638c58 Boot ID: b35eb62018fc4446b8252eb2f2ae9ff5 Operating System: Raspbian GNU/Linux 10 (buster) Kernel: Linux 4.19.66-v7l+ Architecture: arm
Wenn wir uns nun neu mit unserem Offloader verbinden, wird der nunmehr richtige Freifunk-Node-Name auch als Hostname verwendet.
pi@ff-django-raspi:~ $
Uplink per LTE via iOS Gerät
Nebenbei gibt es noch die Möglichkeit, Tethering mit iOS Geräten zu machen. Dazu muss usbmuxd installiert werden. Und in der /etc/network/interfaces ein Interface angelegt werden.
root@raspberrypi:~# apt install usbmuxd libimobiledevice6 root@raspberrypi:~# vi /etc/network/interfaces
/etc/network/interfaces
allow-hotplug eth1 iface eth1 inet dhcp
Am Besten rebootet ihr jetzt einmal.
Danach steckt ihr euer iOS Gerät per USB an während ihr im Hotspot Menü seid und werdet gefragt, ob das PI Zugriff bekommen kann. Das beantwortet ihr mit „Ja“.
Euer PI bezieht sich nun eine IP per DHCP vom iOS Gerät und kann darüber Verbindungen zu den Freifunk Gateways aufbauen.
OLED Display
In dem Beispiel verwenden wir ein OLED Display von AZDelivery mit 128×64 Pixeln. Das schöne an dem Display ist, es funktioniert auch mit 5V und ist damit noch einfacher anzuschließen.
Anschluss/Verkabelung
Angeschlossen wird das Ganze wie folgt:
OLED Pin | GPIO Pin | Notes |
---|---|---|
Vcc | 4 | 5V |
Gnd | 6 | Ground |
SCL | 5 | I2C SCL |
SDA | 3 | I2C SCA |
I2C-Bus aktivieren
Als nächstes aktivieren wir die I2C Schnittstelle und installieren die notwendige Software.
root@raspberrypi:~# echo i2c-bcm2708 >> /etc/modules root@raspberrypi:~# echo i2c-dev >> /etc/modules
root@raspberrypi:~# apt install python3-dev python3-smbus i2c-tools python3-pil python3-pip python3-setuptools python3-rpi.gpio
Bevor wir nun einen Reboot durchführen kontrollieren wir noch, ob in der /boot/config.txt das I2C-Interface auch gestartet wird.
root@raspberrypi:~# vim /boot/config.txt
... # Uncomment some or all of these to enable the optional hardware interfaces # Django : 2019-09-11 - für OLED Display Support aktiviert # default: # dtparam=i2c_arm=on dtparam=i2c_arm=on ...
Nun am Besten einmal rebooten.
root@raspberrypi:~# systemctl reboot
Funktionstest
Danach überprüfen wir ob das Display erkannt wird.
root@raspberrypi:~# i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
Wie man sieht meldet sich das Display unter der Adresse 3c.
Installation der Software-Bibliotheken
Jetzt installieren wir die notwendige Python Library um das Display ansteuern zu können.
root@raspberrypi:~# apt install git fonts-freefont-ttf root@raspberrypi:~# cd /usr/local/src/ root@raspberrypi:~# git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git root@raspberrypi:~# cd Adafruit_Python_SSD1306 root@raspberrypi:~# python3 setup.py install
Anschließend können wir mit ein paar Beispielen probieren ob das Display korrekt funktioniert.
root@raspberrypi:~# cd examples root@raspberrypi:~# python3 /usr/local/src/Adafruit_Python_SSD1306/examples/stats.py
Auf dem Display werden ein paar Systemdaten angezeigt:
Script installieren und anpassen
Nachdem alles alles soweit funktioniert, können wir als nächstes das Bandbreiten Skript installieren, welches auch gleichzeitig die verbundenen BATMAN Clients anzeigt.
Anschließend das Python Skript, welches das Display steuert installieren und anpassen.
root@raspberrypi:~# cd /usr/local/src root@raspberrypi:~# git clone https://github.com/awlx/raspberry-oled-bandwidth root@raspberrypi:~# cd raspberry-oled-bandwidth
Nun passen wir in dem Script folgende Variabelen unseren Gegebenheiten an:
wifi
: Die definierte Schnittstelle unseres WiFi-Devicesvpn
: VPN Definitionenbatman
: BATMAN Definitionenprimary_mac
: MAC des Ethernet-Ports unseres Raspberry 4# ip addr show eth0 | grep link/ether
root@raspberrypi:~# vim /usr/local/src/raspberry-oled-bandwidth/bandwidth.py
- /usr/local/src/raspberry-oled-bandwidth/bandwidth.py
# # Inspired by https://github.com/DarrenBeck/rpi-oled-bandwidth and https://photochirp.com/r-pi/use-raspberry-pi-oled-bandwidth-monitor/ # # Maintained by awlnx - aw@awlnx.space # import subprocess import time import re import Adafruit_GPIO.SPI as SPI import Adafruit_SSD1306 from PIL import Image from PIL import ImageDraw from PIL import ImageFont import math # Adjust to your needs wifi = 'wlan0' vpn = 'fastd-welt' batman = 'bat-welt' # Django : 2019-09-14 # default: primary_mac = 'dc:a6:32:00:6b:59' primary_mac = 'dc:a6:32:01:7f:f0' # We assume 100mbit/s max bandwidth maxRateIn = 10000000 maxRateOut = 10000000 PImaxRateIn = 10000000 PImaxRateOut = 10000000 ### DO NOT EDIT BELOW THIS POINT ### # Raspberry Pi pin configuration: RST = 24 # 128x64 display with hardware I2C: disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST) # Initialize library. disp.begin() # Clear display. disp.clear() disp.display() # Create blank image for drawing. # Make sure to create image with mode '1' for 1-bit color. width = disp.width height = disp.height image = Image.new('1', (width, height)) # Get drawing object to draw on image. draw = ImageDraw.Draw(image) font = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 12) fontsmall = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 10) fontverysmall = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 8) fontmedium = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSans.ttf', 12) #Display Image disp.image(image) disp.display() #Functions def get_network_bytes(interface): for line in open('/proc/net/dev', 'r'): if interface in line: data = line.split('%s:' % interface)[1].split() rx_bytes, tx_bytes = (data[0], data[8]) return (int(rx_bytes), int(tx_bytes)) def drawBar (x, barHeight): # parameters are x, y, end x, end y # draw.rectangle ((x, height - barHeight, x + 10, height -1), outline=255, fill=255) draw.rectangle ((x, 32 - barHeight, x + 8, height - 32), outline=255, fill=255) def drawBarLOW (x, barLOWHeight): # parameters are x, y, end x, end y draw.rectangle ((x, 32 + barLOWHeight, x + 8, height - 32), outline=255, fill=255) def textRate(rate): # rate -> raw bitrate # Returns: SI formatted bitrate if rate == 0: return "0B" rate = rate * 8 size_name = ( "b/s", "kb/s", "mb/s", "gb/s", "tb/s", "pb/s", "eb/s") i = int(math.floor(math.log(rate , 1024))) p = math.pow(1024, i) s = round(rate / p, 1) return "%s %s" % (s, size_name[i]) lastInBytes = get_network_bytes(vpn)[0]; lastOutBytes = get_network_bytes(vpn)[1]; lastPIInBytes = get_network_bytes(wifi)[0]; lastPIOutBytes = get_network_bytes(wifi)[1]; lastTime = time.time() #timed array vars timerTime = time.time() highestSpeedIn = 0 highestSpeedOut = 0 PIhighestSpeedIn = 0 PIhighestSpeedOut = 0 speedArrayIn = [] speedArrayOut = [] PIspeedArrayIn = [] PIspeedArrayOut = [] inMax = 0 outMax = 0 PIinMax = 0 PIoutMax = 0 while (1): time.sleep(2) draw.rectangle((0, 0, width, height), outline=0, fill=0) now = time.time() elapsed = now - lastTime lastTime = now #calculate rates in and out inBytes = get_network_bytes(vpn)[0] currInBytes = (inBytes - lastInBytes) / elapsed lastInBytes = inBytes outBytes = get_network_bytes(vpn)[1] currOutBytes = (outBytes - lastOutBytes) / elapsed lastOutBytes = outBytes PIinBytes = get_network_bytes(wifi)[0] currPIInBytes = (PIinBytes - lastPIInBytes) / elapsed lastPIInBytes = PIinBytes PIoutBytes = get_network_bytes(wifi)[1] currPIOutBytes = (PIoutBytes - lastPIOutBytes) / elapsed lastPIOutBytes = PIoutBytes #max rate last 24 hours calculations if currInBytes > highestSpeedIn: highestSpeedIn = currInBytes if currOutBytes > highestSpeedOut: highestSpeedOut = currOutBytes if currPIInBytes > PIhighestSpeedIn: PIhighestSpeedIn = currPIInBytes if currPIOutBytes > PIhighestSpeedOut: PIhighestSpeedOut = currPIOutBytes if now > timerTime + 3600: print('----------------------------------------------------------------- time expired') timerTime = now speedArrayIn.append (highestSpeedIn) if len (speedArrayIn) > 23: del speedArrayIn[0] inMax = max(speedArrayIn) speedArrayOut.append (highestSpeedOut) if len (speedArrayOut) > 23: del speedArrayOut[0] outMax = max(speedArrayOut) highestSpeedIn = 0 highestSpeedOut = 0 PIspeedArrayIn.append (PIhighestSpeedIn) if len (PIspeedArrayIn) > 23: del PIspeedArrayIn[0] PIinMax = max(PIspeedArrayIn) PIspeedArrayOut.append (PIhighestSpeedOut) if len (PIspeedArrayOut) > 23: del PIspeedArrayOut[0] PIoutMax = max(PIspeedArrayOut) PIhighestSpeedIn = 0 PIhighestSpeedOut = 0 #adjust these in each loop in case we find a faster speed inMax = max(inMax, highestSpeedIn) outMax = max(outMax, highestSpeedOut) PIinMax = max(PIinMax, PIhighestSpeedIn) PIoutMax = max(PIoutMax, PIhighestSpeedOut) #draw graph inHeight = 0.0 outHeight = 0.0 PIinHeight = 0.0 PIoutHeight = 0.0 if currInBytes > 0: inHeight = float(currInBytes / maxRateIn) * 32 if currOutBytes > 0: outHeight = float(currOutBytes / maxRateOut) * 32 if currPIInBytes > 0: PIinHeight = float(currPIInBytes / PImaxRateIn) * 32 if currPIOutBytes > 0: PIoutHeight = float(currPIOutBytes / PImaxRateOut) * 32 drawBar (0, inHeight) drawBar (10, PIinHeight) drawBarLOW (0, outHeight) drawBarLOW (10, PIoutHeight) #write rates draw.text((26,38), textRate(currInBytes), font=font, fill=255) draw.text((26,50), textRate(currOutBytes), font=font, fill=255) draw.text((81,38), textRate(currPIInBytes), font=font, fill=255) draw.text((81,50), textRate(currPIOutBytes), font=font, fill=255) # Batman Clients clients = subprocess.check_output("batctl -m " + batman + " tl | egrep -v '(MainIF|" + primary_mac + ")' | egrep -o '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' | wc -l", shell=True).split().pop() draw.text((0,48), "Clients", font=fontverysmall, fill=255) draw.text((10,55), clients.decode("utf-8"), font=fontverysmall, fill=255) #max rates draw.text((36,0), "VPN", font=fontsmall, fill=255) draw.text((26,10), textRate(inMax), font=fontsmall, fill=255) draw.text((26,20), textRate(outMax), font=fontsmall, fill=255) draw.text((90,0), "Wifi", font=fontsmall, fill=255) draw.text((81,10), textRate(PIinMax), font=fontsmall, fill=255) draw.text((81,20), textRate(PIoutMax), font=fontsmall, fill=255) disp.image(image) disp.display()
Nun können das Script erst einmal manuell anstarten und prüfen ob die gewünschten Informationen richtig angezeigt werden.
root@raspberrypi:~# /usr/bin/python3 /usr/local/src/raspberry-oled-bandwidth/bandwidth.py
Um nun nicht jedes mal beim Starten des Offloaders/Gateways manuell starten müssen, legen wir uns noch ein systemd-Script an.
root@raspberrypi:~# vim /etc/systemd/system/oled-bandwidth.service
- /etc/systemd/system/oled-bandwidth.service
# Django : 2019-09-11 [Unit] After=network.target [Service] ExecStart=/usr/bin/python3 /usr/local/src/raspberry-oled-bandwidth/bandwidth.py [Install] WantedBy=default.target
Anschließend Informieren wir unser System über unser definiertes Daemon-Startscript und aktivieren dies auch gleich noch.
root@raspberrypi:~# systemctl daemon-reload root@raspberrypi:~# systemctl enable oled-bandwidth.service
Zu guter letzte rebooten wir nun unseren Rechner.
root@raspberrypi:~# systemctl reboot