Bau eines Freifunk-Offloaders auf Basis eines Raspberry 4B

Bild: Freifunk München Logo

Bei größeren Installationen, wie z.B. in Flüchtlingsunterkünften, Wohnheimen, oder Veranstaltungen bzw. Veranstaltungsräumen gelangt man mit den gängigen Plasteroutern sehr schnell an deren Leistungsgrenzen. Die zeigt sich vor allem beim Datendurchsatz, da die in den Routern verbauten CPUs an ihre Grenzen kommen, da diese nicht für eine permanente Ver- und Entschlüsselung von großen Datenmengen ausgelegt sind.
In diesem Konfigurationsbeispiel wollen wir möglichst einfach und schnell einen Offloader für Freifunk München auf Basis eines Raspberry 4B befassen. Dabei gehen wir auf unterschiedliche Konfigurations-Optionen ein und wollen dennoch die Einstiegshürden für den ungeübteren Ansible und Linux-User möglichst tief ansetzen.

Als Basis für die Konfiguration setzen wir beim sehr gut dokumentierten Artikel von @awlnx aus dem Freifunk WIKI auf.
Nicht unerwähnt darf auch @lqb bleiben, der mit entscheidenden Tips zum Gelingen des Ansible-Playbooks beigetragen hat!

Inhalt

Das Kapitel hier ist in folgende Abschnitte strukturiert.

Wer also z.B. bereits einen SSH-Schlüssel sein eigen nennt oder Grundlagen zu Ansible bereits kennt und installiert hat, kann natürlich sofort beim Playbook bzw. dessen Ausführung einsteigen und die nachfolgenden Informationen überspringen.

Folgende Abschnitte beschreiben den eigentlichen Bau des Freifunk-Offloaders mit Ansible-Unterstützung und ist somit der ideale Einsprungpunkt für den versierten LINUX-Admin mit entsprechenden Ansible-Kenntnissen.:

Grundlegende Informationen rund um die SSH1) und deren Umgang bei der täglichen Arbeit finden sich im Kapitel Secure Shell hier im WIKI.

Damit wir selbst für spätere Administrationsaufgaben und auch unser Ansible-Admin-Host Verbindungen mit Hilfe der SSH2) zu unserem Offloader aufbauen kann, benötigen wir natürlich entsprechendes Schlüsselmaterial, abhängig vom jeweiligen Zielsystem bzw. den kryptographischen Eigenschaften.

Bei der Erstellung wollen wir statt einesRSA-Keys auf zeitgemäße und sicherere ed25519 Schlüssel verwenden. Ed25519 ist ein Elliptic Curve Signature Schema, welches beste Sicherheit bei vertretbaren Aufwand verspricht, als ECDSA oder DSA dies der Fall ist. Zur Auswahl sicherer kryptografischer Kurven bei der Elliptic-Curve Cryptography findet man auf der Seite hier hilfreiche Erklärungen und eine Gegenüberstellung der möglichen verschiedenen Alternativen. Weitere Infos zu den ED25519-Schlüsseln und der SSH finden sich im entsprechenden Kapitel hier im WIKI.

Wir erstellen uns nun einen ED25519-Schlüssel (-t), mit einer festen Schlüssellänge. Der Parameter (-a) beschreibt dabei die Anzahl der KDF-Schlüsselableitfunktion (siehe manpage von ssh-keygen). Wir verwenden als Beschreibung FFMUC Remote-User (-C) und als Ziel-/Speicherort ~/.ssh/id_ed25519_ffmuc (-f).

  $ ssh-keygen -t ed25519 -a 100 -C 'FFMUC Remote-User' -f ~/.ssh/id_ed25519_ffmuc
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in ~/.ssh/id_ed25519_ffmuc.
Your public key has been saved in ~/.ssh/id_ed25519_ffmuc.pub.
The key fingerprint is:
SHA256:jTZQUDbCqZaV64+Dj4n90+15+A+933K*fx3L4iUCBY3kKMQ FFMUC Remote-User
The key's randomart image is:
+--[ED25519 256]--+
|     o+==.oo     |
|     .E+ +.+.    |
|     ++.. = *    |
|    +..+ + O .   |
|   ...  S + o .  |
|     ... E *   . |
|      .oo o + + .|
|      .... . =E  |
|       .. + ooo  |
+----[SHA256]-----

Bild: Ansible Logo


Grundlegende Informationen zu Ansible und dessen Umgang bei der täglichen Arbeit finden sich im Kapitel Ansible hier im WIKI.

Je nach verwendeter Systemumgebung installieren wir nun das vom Paketmaintainer zur Verfügung gestellte RPM bzw. DEB Paket. Im Falle von RedHat basierenden Systemen wie CentOS oder Fedora benutzen wir das Paketverwaltungswerkzeug YUM/DNF oder im Falle von Debian und Ubuntu das Werkzeug APT.

  • RPM basierende Systeme:
     # dnf install ansible

    bzw.

     # yum install ansible
  • DEB basierende Systeme:
     # apt install ansible

    bzw. als eigeloggter User via sudo mit

     $ sudo apt install ansible

Verzeichnis-Struktur

Gemäß Ansible's Best Practices gibt es durchaus einige Möglichkeiten wie man seine Playbooks organisiert. In aller Regel wird man hier die eigenen individuellen Bedürfnisse (seiner Unternehmung) vornan stellen.

Jedoch empfiehlt es sich durchaus auf Empfohlenes zurückzugreifen! So empfiehlt es sich zum Beispiel auch, Rollen anstelle von Aufgaben zu verwenden, da dies wesentlich bei der Flexibilität und besseren Organisation der eigenen Playbooks/Codes helfen!

Ansible bietet zwei Beispiele für Verzeichnis-Layouts. Wir werden im folgen Beispiel uns eine Umgebung aufbauen, in der unser Inventory, also unsere Hosts und Nodes, in mehreren groups und childs aufteilen.

Mit dieser Struktur sind wir dann in der Lage jede Inventardatei mit ihrer group_vars und host_vars in ein separates Verzeichnis zu packen. Fernen können wir so einfach neue Rollen roleserzeugen, in dem wir dann einfach die bereits vorgefertigte Rollenvorlage common kopieren.

Werfen wir also einfach mal auf die beschrieben Verzeichnisstruktur einen genaueren Blick. Die entsprechende Verwendung der einzelnen Verzeichnisse und DAteien ist in der Aufstellung entsprechend angegeben.

ansible/
├── filter_plugins                 # (optionales) Verzeichnis für individuelle filter plugins
├── library                        # (optionales) Verzeichnis für benutzerdefinierte Module
├── module_utils                   # (optionales) Verzeichnis für benutzerdefinierte module_utils zur Unterstützung von Modulen
│
├── inventories                    # Verzeichnis für die einzelnen (unterschiedlichen) Invenory
│   ├── production                 # Verzeichnis für die Hosts aus der Gruppe production
│   │   ├── hosts.yml              # YML-Datei mit den Host-Definitionen aus der Gruppe production
│   │   ├── group_vars             # Verzeichnis für die Gruppenspezifischen Variablen der Gruppe production
│   │   └── host_vars              # Verzeichnis für die Hostspezifischen Variablen der Gruppe production
│   │    
│   └── staging                    # Verzeichnis für die Hosts aus der Gruppe staging
│       ├── hosts.yml              # YML-Datei mit den Host-Definitionen aus der Gruppe production
│       ├── group_vars             # Verzeichnis für die Gruppenspezifischen Variablen der Gruppe 
│       └── host_vars              # Verzeichnis für die Hostspezifischen Variablen der Gruppe production
│
├── roles                          # Verzeichnis für die einzelnen (unterschiedlichen) Rollen
│   └── common                     # Verzeichnis "role" common mit seinen entsprechenden Definitionen - Vorlage zum Kopieren
│       ├── defaults               # Verzeichnis "defaults"
│       │   └── main.yml           # Standardvariablen mit niedrigerer Priorität für diese Rolle
│       ├── files                  # Verzeichnis "files"
│       │   └── main.yml           # (Skript-)Dateien zur Verwendung als Kopier- bzw. Script-Rressource
│       ├── handlers               # Verzeichnis "handlers"
│       │   └── main.yml           # Datei mit den Definitionen zu den rollenspezifischen "handlers"
│       ├── library                # Verzeichnis für benutzerdefinierte Module einer der Rolle (role) "common"
│       ├── lookup_plugin          # Verzeichnis für weitere Arten von Plugins, wie in diesem Fall "lookup"
│       ├── meta                   # Verzeichnis "meta" für Rollenspezifische Definitionen/Abhängigkeiten
│       │   └── main.yml           # Datei mit Rollenspezifischen Definitionen
│       ├── module_utils           # Verzeichnis "module_utils", die benutzerdefinierte module_utils der Rollen enthalten könnte
│       ├── tasks                  # Verzeichnis "tasks" für kleinere Aufgabendateien
│       │   └── main.yml           # Datei für kleinere Aufgaben, falls diese benötigt werden würden 
│       ├── templates              # Verzeichnis mit den Templates
│       │   └── main.j2            # Template-Datei mit dem Dateisuffix/-Ende .j2
│       └── vars                   # Verzeichnis "vars", mit den zu dieser Rolle zugeordneten Variablen
│           └── main.yml           # Datei mit den Rollenspezifischen Variablen
│
└── site.yml                       # master playbook

Um dieses Verzeichnis-Layout einfach und schnell auf den Weg zu bringen, verwenden wir die nachfolgend gezeigten zwei Befehle bzw. genauer gesagt die beiden Befehlskette:

 $ mkdir -p ~/ansible/inventories/{production,staging}/{group_vars,host_vars} \
            ~/ansible/{library,module_utils,filter_plugins} \
            ~/ansible/roles/common/{tasks,handlers,templates,files,vars,defaults,meta,library,module_utils,lookup_plugin}
 $ touch    ~/ansible/inventories/{production,staging}/hosts.yml \
            ~/ansible/site.yml \
            ~/ansible/roles/common/{tasks,handlers,templates,files,vars,defaults,meta}/main.yml

Ansible-Konfigurationsdatei

Als nächstes kopieren wir uns die Vorlage-Konfiguratinsdatei aus dem Verzeichnis /etc/ansible/ in unser Homeverzeichnis.

 $ cp /etc/ansible/ansible.cfg ~/.ansible.cfg

Unter dem Konfigurationsgruppe [ defaults ] setzen wir den Parameter inventory = ~/ansible/inventories/production/hosts und interpreter_python = auto_silent. Beim ersten Parameter zeigen wir Ansible, wo die Host-Definitionen zu finden sind. beim Parameter interpreter_python geben wir an, dass keine Ausgabe zu den Angaben des Pfads zum Python-Interpreter auf dem Raspberry ausgegeben werden soll. Der Parameter connect_timeout definiert, wie lange eine persistente Verbindung bestehen darf, bevor diese hart getrennt wird. Weitere Information zu den Konfigurationsparametern finden sie in der Dokumentation der Konfigurationsoptionen zu Ansible.

 $ vim ~/.ansible.cfg

Im Ganzen ergibt sich dann hier die doch überschaubare Konfigurationsdatei zu Ansible.

 $ egrep -v '(^.*#|^$)' ~/.ansible.cfg 
[defaults]
inventory          = ~/ansible/inventories/production/hosts
interpreter_python = auto_silent
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
connect_timeout = 30
[accelerate]
[selinux]
[colors]
[diff]

Host-Definitionsdatei

Die Definition unseres Hosts mit den tzugehörigen Variablen beziehen wir später aus dem Ansible Playbook Archiv. Somit müssen wir hier nichts extra vorbereiten!

SSH Konfigurationsdatei

Damit wir unseren Raspberry auch direkt über den zuvor definierten Namen ansprechen können, definieren wir nun noch in unserer SSH-Konfigurationsdatei ~/.ssh/config des Clients diesen Host.

 $ vim ~/.ssh/config
Host raspberry-wireguard
     Hostname 10.0.10.29
     Port 22
     User pi
     IdentitiesOnly=yes
     Protocol 2
     IdentityFile ~/.ssh/id_ed25519_ffmuc

Beim Parameter Hostname geben wir die IP-Adresse an, die unser DHCP-Server dem Raspberry verpasst an; in obigen Konfigurationsbeispiel hat unser Raspberry die IP-Adresse 10.0.10.29. Die Datei mit dem Eingangs erzeugten SSH-Schlüssel geben wir beim Parameter IdentityFile an.

Nun können wir uns „endlich“ daran machen unseren Offloader auf Basis eines Raspberry 4B zu bauen. Hierzu greifen wir auf folgendes Playbook zurück und laden es uns auf unseren Rechner.:

 $ wget \
       https://wiki.mailserver.guru/lib/exe/fetch.php/centos:ansible:ansible-playbook-ffmuc-offloader-auf_basis_raspberry-4b.v4.tar.gz \
       -O ansible-playbook-ffmuc-offloader-auf_basis_raspberry-4b.tar.gz

Anschließend entpacken wir es an Ort und Stelle.

 $ tar -xvf ansible-playbook-ffmuc-offloader-auf_basis_raspberry-4b.tar.gz

Somit ergibt sich folgende Verzeichnis- und Dateistruktur:

ansible
├── filter_plugins
├── inventories
│   ├── production
│   │   ├── group_vars
│   │   ├── hosts.yml
│   │   └── host_vars
│   └── staging
│       ├── group_vars
│       ├── hosts.yml
│       └── host_vars
├── library
├── module_utils
├── roles
│   ├── basic
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── library
│   │   ├── lookup_plugin
│   │   ├── meta
│   │   │   └── main.yml
│   │   ├── module_utils
│   │   ├── tasks
│   │   │   ├── hostname.yml
│   │   │   ├── hosts.yml
│   │   │   ├── main.yml
│   │   │   ├── reboot.yml
│   │   │   ├── rfkill.yml
│   │   │   ├── update.yml
│   │   │   └── usercomment.yml
│   │   ├── templates
│   │   │   ├── hosts.j2
│   │   │   └── main.yml
│   │   └── vars
│   │       └── main.yml
│   ├── batman
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── library
│   │   ├── lookup_plugin
│   │   ├── meta
│   │   │   └── main.yml
│   │   ├── module_utils
│   │   ├── tasks
│   │   │   ├── backport.yml
│   │   │   ├── batmanstart.yml
│   │   │   ├── compile.yml
│   │   │   ├── install.yml
│   │   │   ├── interfaceconfigure.yml
│   │   │   ├── main.yml
│   │   │   ├── modulloads.yml
│   │   │   ├── reboot.yml
│   │   │   └── utilsinstall.yml
│   │   ├── templates
│   │   │   ├── batman-adv.module.j2
│   │   │   ├── dkms.j2
│   │   │   ├── interfaces.j2
│   │   │   └── main.yml
│   │   └── vars
│   │       └── main.yml
│   ├── client-mesh
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── library
│   │   ├── lookup_plugin
│   │   ├── meta
│   │   │   └── main.yml
│   │   ├── module_utils
│   │   ├── tasks
│   │   │   ├── batmanmitwifi.yml
│   │   │   ├── batmanohnewifi.yml
│   │   │   ├── clientohnemesh.yml
│   │   │   ├── getvxlanid.yml
│   │   │   ├── main.yml
│   │   │   ├── meshohneclient.yml
│   │   │   └── meshundclient.yml
│   │   ├── templates
│   │   │   ├── interfaces_client_ohne_mesh.j2
│   │   │   ├── interfaces_mesh_mit_client.j2
│   │   │   ├── interfaces_mesh_ohne_client.j2
│   │   │   ├── main.yml
│   │   │   ├── rclocal_both.j2
│   │   │   └── rclocal_vxlan.j2
│   │   └── vars
│   │       └── main.yml
│   ├── common
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── library
│   │   ├── lookup_plugin
│   │   ├── meta
│   │   │   └── main.yml
│   │   ├── module_utils
│   │   ├── tasks
│   │   │   └── main.yml
│   │   ├── templates
│   │   │   └── main.yml
│   │   └── vars
│   │       └── main.yml
│   ├── ext-respondd
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── library
│   │   ├── lookup_plugin
│   │   ├── meta
│   │   │   └── main.yml
│   │   ├── module_utils
│   │   ├── tasks
│   │   │   ├── aliasgenerate.yml
│   │   │   ├── configgenerate.yml
│   │   │   ├── copyconfig.yml
│   │   │   ├── gitclone.yml
│   │   │   ├── gitinstall.yml
│   │   │   ├── main.yml
│   │   │   └── servicestartup.yml
│   │   ├── templates
│   │   │   ├── ext-respondd_alias.json.j2
│   │   │   ├── ext-respondd_config.json.j2
│   │   │   └── main.yml
│   │   └── vars
│   │       └── main.yml
│   ├── fastd
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── library
│   │   ├── lookup_plugin
│   │   ├── meta
│   │   │   └── main.yml
│   │   ├── module_utils
│   │   ├── tasks
│   │   │   ├── directorygenerate.yml
│   │   │   ├── fastdconfigure.yml
│   │   │   ├── fastdgetsocket.yml
│   │   │   ├── fastdinstall.yml
│   │   │   ├── fastdkeygen.yml
│   │   │   ├── fastdsecretkeyget.yml
│   │   │   ├── fastdstartup.yml
│   │   │   └── main.yml
│   │   ├── templates
│   │   │   ├── fastd.j2
│   │   │   └── main.yml
│   │   └── vars
│   │       └── main.yml
│   ├── final
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── library
│   │   ├── lookup_plugin
│   │   ├── meta
│   │   │   └── main.yml
│   │   ├── module_utils
│   │   ├── tasks
│   │   │   ├── main.yml
│   │   │   └── reboot.yml
│   │   ├── templates
│   │   │   └── main.yml
│   │   └── vars
│   │       └── main.yml
│   ├── hostapd
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── library
│   │   ├── lookup_plugin
│   │   ├── meta
│   │   │   └── main.yml
│   │   ├── module_utils
│   │   ├── tasks
│   │   │   ├── configure.yml
│   │   │   ├── genconfig.yml
│   │   │   ├── install.yml
│   │   │   ├── main.yml
│   │   │   ├── servicestartup.yml
│   │   │   └── wlanbridging.yml
│   │   ├── templates
│   │   │   ├── hostapd.j2
│   │   │   ├── main.yml
│   │   │   └── rclocal_wifi.j2
│   │   └── vars
│   │       └── main.yml
│   ├── oled
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── library
│   │   ├── lookup_plugin
│   │   ├── meta
│   │   │   └── main.yml
│   │   ├── module_utils
│   │   ├── tasks
│   │   │   ├── adafruitclone.yml
│   │   │   ├── adafruitconfig.yml
│   │   │   ├── i2c_arm.yml
│   │   │   ├── i2c-bcm2708.yml
│   │   │   ├── i2c-dev.yml
│   │   │   ├── main.yml
│   │   │   ├── packages.yml
│   │   │   ├── reboot.yml
│   │   │   ├── scriptclone.yml
│   │   │   ├── scriptconfig.yml
│   │   │   ├── scriptstartup.yml
│   │   │   └── scriptstart.yml
│   │   ├── templates
│   │   │   ├── bandwidth.j2
│   │   │   ├── config.j2
│   │   │   ├── main.yml
│   │   │   └── oled-bandwidth.j2
│   │   └── vars
│   │       └── main.yml
│   ├── vxlan
│   │   ├── defaults
│   │   │   └── main.yml
│   │   ├── files
│   │   │   └── main.yml
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── library
│   │   ├── lookup_plugin
│   │   ├── meta
│   │   │   └── main.yml
│   │   ├── module_utils
│   │   ├── tasks
│   │   │   ├── configure.yml
│   │   │   ├── main.yml
│   │   │   └── vxlanstart.yml
│   │   ├── templates
│   │   │   ├── main.yml
│   │   │   ├── systemd-service-file.j2
│   │   │   └── vxlan-init.j2
│   │   └── vars
│   │       └── main.yml
│   └── wireguard
│       ├── defaults
│       │   └── main.yml
│       ├── files
│       │   └── main.yml
│       ├── handlers
│       │   └── main.yml
│       ├── library
│       ├── lookup_plugin
│       ├── meta
│       │   └── main.yml
│       ├── module_utils
│       ├── tasks
│       │   ├── brokerinform.yml
│       │   ├── checkup.yml
│       │   ├── configuration.yml
│       │   ├── genkeys.yml
│       │   ├── genlinklocal.yml
│       │   ├── install.yml
│       │   ├── main.yml
│       │   └── wireguardstart.yml
│       ├── templates
│       │   ├── broker.j2
│       │   ├── checkup.j2
│       │   ├── crontab.j2
│       │   ├── main.yml
│       │   └── uplink.j2
│       └── vars
│           └── main.yml
└── wireguard-offloader.yml

Nachfolgend finden wir die Inhalte der einzelnen Dateien die im ansible-playbook enthalten sind:

Inventory-Definition

~/ansible/inventories/production/hosts.yml
--- #YAML start syntax (optional)
ffmuc:
  children:
    ffmuc_deb:
      vars:
        ansible_ssh_user: pi
      hosts:
        raspberry-wireguard:
          wireguard_ports:
            muc_cty:            40002
            muc_nord:           40003
            muc_ost:            40004
            muc_sued:           40005
            muc_west:           40006
            uml_nord:           40007
            uml_ost:            40008
            uml_sued:           40009
            uml_west:           40010
            gauting:            40012
            freising:           40013
            welt:               40011
          vxlan_ids:
            muc_cty:            10758607
            muc_nord:           15521492
            muc_ost:            2948862
            muc_sued:           8599288
            muc_west:           7318933
            uml_nord:           5705961
            uml_ost:            4892713
            uml_sued:           16544703
            uml_west:           16677749
            gauting:            16175732
            freising:           12937858
            welt:               16306234
          gw_linklocal:
            gw04:               "fe80::27c:16ff:fec0:6c74"
            gw05:               "fe80::281:8eff:fef0:73aa"
          gw_publickey:
            gw04:               "TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g="
            gw05:               "igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg="      
          gw_vxlan_ids:
            muc_cty:            3836090
            muc_nord:           1920014
            muc_ost:            12097488
            muc_sued:           12815947
            muc_west:           29149
            uml_nord:           403289
            uml_ost:            12645856
            uml_sued:           12090508
            uml_west:           935867
            gauting:            4681119
            freising:           4669918
            welt:               4831583
          batman_adv_version:   "2020.4"
          ffmuc_segment:        "muc_ost"
          ffmuc_gateway:        "gw04"
          raspberry_hostname:   "raspbian-ansible-offloader"
          node_contact_address: "https://bit.ly/2VxGoXp"
          raspberry_latitude:   "48.239094621"
          raspberry_longitude:  "11.558936834"
          raspberry_wifi:       "ja"
          raspberry_clientvlan: "123"
          raspberry_meshvlan:   "456"
          raspberry_oled:       "ja"
          dtparam:              "i2c_arm=on"
... #YAML ende syntax (optional)

Playbook "main"

~/ansible/wireguard-offloader.yml
--- # Ansible Playbook für (statische) Konfiguration eines Offloader auf Basis eines Raspberry PI 4B
- name:         raspi_offloader_file.yml 
  hosts:        raspberry-wireguard
  become:       yes
  become_user:  root
 
  roles:
    - basic         # Basiskonfiguration des Hosts (Host-/Username anpassen und System Updaten)
    - batman        # Installation und Konfiguration der BATMAN Kernel-Module
    - wireguard     # Installation und Konfiguration des wireguard Tunnels
    - vxlan         # Konfiguration von VXLAN für wireguard-Tunnel-Verbindung in Richtung Gateway
    - ext-respondd  # Installation und Konfiguration des ext-respondd (Statistiken für https://map.ffmuc.net)
    - hostapd       # Installation und Konfiguration des hostap Treibers für den WiFi-Support
    - client-mesh   # Grundkonfiguration von Client und/oder Meshing (V)LANs
    - oled          # Konfiguration eines OLEDisplays sofern eines am Respberry 4B verbaut ist
    - final         # Reboot nach Abschluss der Konfiguration unseres Offloaders 
 
... # YML Ende

Rolle "basic"

Tasks
~/ansible/roles/basic/tasks/main.yml
--- # Grundkonfiguration und Systemupgrade des Raspberry Pi OS
- include: hostname.yml                 # Hostname ändern
- include: hosts.yml                    # /etc/hosts anpassen
- include: usercomment.yml              # Beschreibung des User 'pi' anpassen
- include: rfkill.yml                   # Service rfkill bei Raspberry Pi OS deaktivieren
- include: update.yml                   # Update und Upgrade der APT-Pakete
- include: reboot.yml                   # Reboot nach update
~/ansible/roles/basic/tasks/hostname.yml
---
  - name: "Hostname ändern"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: 
      cmd: hostnamectl set-hostname {{ raspberry_hostname }}
~/ansible/roles/basic/tasks/hosts.yml
---
  - name: "Template Konfigurationsdatei für /etc/hosts an Ort und Stelle kopieren und Variablen anpassen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/hosts.j2
      dest: /etc/hosts
~/ansible/roles/basic/tasks/usercomment.yml
---
  - name: "Beschreibung des User 'pi' anpassen"
    # https://docs.ansible.com/ansible/latest/modules/user_module.htm
    user: 
      name: pi
      comment: "Raspberry Pi OS System User"
      state: present
~/ansible/roles/basic/tasks/rfkill.yml
---
  - name: "Service rfkill am Raspberry deaktivieren"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: 
      cmd: rfkill unblock wifi
~/ansible/roles/basic/tasks/update.yml
---
  - name: "Update und Upgrade der APT-Pakete"
    # https://docs.ansible.com/ansible/latest/modules/apt_module.html
    apt: 
      upgrade: dist
      update_cache: yes
~/ansible/roles/basic/tasks/reboot.yml
---
  - name: "Reboot nach update"
    # https://docs.ansible.com/ansible/latest/modules/reboot_module.html
    reboot:
Templates
~/ansible/roles/basic/templates/hosts.j2
127.0.0.1	localhost {{ raspberry_hostname }}
::1		localhost ip6-localhost ip6-loopback
ff02::1		ip6-allnodes
ff02::2		ip6-allrouters

Rolle "batman"

Tasks
~/ansible/roles/batman/tasks/main.yml
--- # Installation und Konfiguration von BATMAN
- include: install.yml                  # Download des aktuellen BATMAN Archives
- include: compile.yml                  # BATMAN Kernel-Module erzeugen
- include: modulloads.yml               # MATMAN-ADV und DUMMY Module laden
- include: backport.yml                 # Buster-backports für Installation von batctl vorbereiten
- include: utilsinstall.yml             # Installation der bridge-utils und batctl 
- include: batmanstart.yml              # Aktivierung von BATMAN_V
- include: interfaceconfigure.yml       # Konfiguration der Interfaces
- include: reboot.yml                   # Rebot nach Ende des Installationsschritts
~/ansible/roles/batman/tasks/install.yml
---
  - name: "*BATMAN Installation* : Download des aktuellen BATMAN Archives"
    # https://docs.ansible.com/ansible/latest/modules/get_url_module.html
    get_url: 
      url: https://downloads.open-mesh.org/batman/releases/batman-adv-{{ batman_adv_version }}/batman-adv-{{ batman_adv_version }}.tar.gz
      dest: /usr/src/batman-adv-{{ batman_adv_version }}.tar.gz
      mode: '0644'
 
  - name: "*BATMAN Installation* : Entpacken des BATMAN-Archives"
    # https://docs.ansible.com/ansible/latest/modules/unarchive_module.html
    unarchive:
      src: /usr/src/batman-adv-{{ batman_adv_version }}.tar.gz
      dest: /usr/src
      remote_src: yes
~/ansible/roles/batman/tasks/compile.yml
---
  - name: "*BATMAN compile* : Installation des Dynamic Kernel Module Support Framework und der Header Files für den Raspberry Pi OS Linux Kernel"
    # https://docs.ansible.com/ansible/latest/modules/apt_module.html
    apt: 
      update_cache: yes
      pkg:
        - dkms
        - raspberrypi-kernel-headers
      state: present
 
  - name: "*BATMAN compile* : Rebuild BATMAN Kernel Header Dateien"
    # https://docs.ansible.com/ansible/latest/modules/make_module.html
    make:
      chdir: /usr/src/linux-headers-{{ ansible_kernel }}
      target: scripts
    ignore_errors: yes
 
  - name: "*BATMAN compile* : Anlegen der dkms.conf für Dynamic Kernel Module Support"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template:
      src: templates/dkms.j2
      dest: /usr/src/batman-adv-{{ batman_adv_version }}/dkms.conf
 
  - name: "*BATMAN compile* : Dynamic Kernel Module Support hinzufügen"
    # https://docs.ansible.com/ansible/latest/modules/command_module.html
    command: dkms add -m batman-adv -v {{ batman_adv_version }}
    register: ret
    failed_when: ret.rc != 0 and ret.rc != 3
    changed_when: ret.rc == 0
 
  - name: "*BATMAN compile* : Dynamic Kernel Module bauen"
    # https://docs.ansible.com/ansible/latest/modules/command_module.html
    command: dkms build -m batman-adv -v {{ batman_adv_version }}
 
  - name: "*BATMAN compile* : BATMAN Dynamic Kernel Module installieren"
    # https://docs.ansible.com/ansible/latest/modules/command_module.html
    command: dkms install -m batman-adv -v {{batman_adv_version }}
~/ansible/roles/batman/tasks/modulloads.yml
---
  - name: "*BATMAN load-modules* : Laden der BATMAN Dynamic Kernel Module beim Booten sicherstellen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/batman-adv.module.j2
      dest: /etc/modules-load.d/batman-adv.module.conf
 
  - name: "*BATMAN load-modules* : dummy Modul laden"
    # https://docs.ansible.com/ansible/latest/modules/modprobe_module.html
    modprobe: 
      name: dummy
      state: present
 
  - name: "*BATMAN load-modules* : BATMAN-ADV Modul laden"
    # https://docs.ansible.com/ansible/latest/modules/modprobe_module.html
    modprobe: 
      name: batman_adv
      state: present
~/ansible/roles/batman/tasks/backport.yml
---
  - name: "*buster-backport* : PGP-Schlüssel 04EE7237B7D453EC für buster-backports installieren"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell:
      cmd: apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-key 04EE7237B7D453EC
 
  - name: "*buster-backport* : PGP-Schlüssel 648ACFD622F3D138 für buster-backports installieren"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell:
      cmd: apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-key 648ACFD622F3D138
 
  - name: "*buster-backport* : buster-backports dem System bekannt machen"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell:
      cmd: echo "deb http://deb.debian.org/debian buster-backports main" | tee /etc/apt/sources.list.d/buster-backports.list
 
  - name: "*buster-backport* : APT-Cache aktualisieren" 
    # https://docs.ansible.com/ansible/latest/modules/apt_module.html
    apt:
      update_cache: yes
~/ansible/roles/batman/tasks/utilsinstall.yml
---
  - name: "*utils-installation* : Installation der bridge-utils"
    # https://docs.ansible.com/ansible/latest/modules/apt_module.html
    apt: 
      #update_cache: yes
      pkg:
       - bridge-utils
       - dnsutils
       - vim
      state: present
 
  - name: "*utils-installation* : Installation der bridge-utils"
    # https://docs.ansible.com/ansible/latest/modules/apt_module.html
    apt:
      #update_cache: yes
      pkg:
      - batctl
      default_release: buster-backports
      state: present
~/ansible/roles/batman/tasks/batmanstart.yml
---
  - name: "*BATMAN-ADV* : Aktivierung von BATMAN_V"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: 
      cmd: batctl ra BATMAN_V
~/ansible/roles/batman/tasks/interfaceconfigure.yml
---
  - name: "*BATMAN-ADV Interfaces* : Konfiguration des Interfaces"  
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template:
      src: templates/interfaces.j2
      dest: /etc/network/interfaces
~/ansible/roles/batman/tasks/reboot.yml
---
  - name: "*BATMAN Installation* : Reboot nach Ende der BATMAN Installationsschritte"
    # https://docs.ansible.com/ansible/latest/modules/reboot_module.html
    reboot:
Templates
~/ansible/roles/batman/templates/batman-adv.module.j2
#
# Load batman-adv module on system boot
#
batman-adv
dummy
~/ansible/roles/batman/templates/dkms.j2
PACKAGE_NAME=batman-adv
PACKAGE_VERSION={{ batman_adv_version }}
 
DEST_MODULE_LOCATION=/extra
BUILT_MODULE_NAME=batman-adv
BUILT_MODULE_LOCATION=net/batman-adv
 
MAKE="'make'"
CLEAN="'make' clean"
 
AUTOINSTALL="yes"
~/ansible/roles/batman/templates/interfaces.j2
# 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:
# source-directory /etc/network/interfaces.d
 
auto eth0
iface eth0 inet dhcp
 
auto br-{{ ffmuc_segment }}
iface br-{{ ffmuc_segment }} inet dhcp
        bridge-ports bat-{{ ffmuc_segment }}
        pre-up /usr/sbin/batctl ra BATMAN_V
        pre-up /sbin/ip link add dummy-{{ ffmuc_segment }} 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-{{ ffmuc_segment }}
        pre-up /sbin/ip link set dummy-{{ ffmuc_segment }} up
        pre-up /usr/sbin/batctl meshif bat-{{ ffmuc_segment }} if add dummy-{{ ffmuc_segment }}
        pre-up /sbin/ip link set bat-{{ ffmuc_segment }} up
        pre-up /usr/sbin/batctl meshif bat-{{ ffmuc_segment }} 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-{{ ffmuc_segment }}
        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-{{ ffmuc_segment }}

Rolle "wireguard"

Tasks
~/ansible/roles/wireguard/tasks/main.yml
--- # Installation und Konfiguration von WIREGUARD
- include: install.yml                  # Installation des wireguard-Paketes
- include: genkeys.yml                  # Schlüsselmaterial erzeugen
- include: genlinklocal.yml             # lokale link-local IPv6 Adresse generieren
- include: configuration.yml            # Konfigurationsdatei kopieren und anpassen
- include: brokerinform.yml             # Public-Key unseres Nodes an den Broker übermitteln 
- include: wireguardstart.yml           # Aktivierung des wireguard client-daemon
- include: checkup.yml                  # Wireguard überprüfen
~/ansible/roles/wireguard/tasks/install.yml
---
  - name: "*wireguard* : Installation von wireguard"
    # https://docs.ansible.com/ansible/latest/modules/apt_module.html
    apt: 
      #update_cache: yes
      pkg:
       - wireguard
      state: present
~/ansible/roles/wireguard/tasks/genkeys.yml
---
  - name: "*wireguard* : Schlüsselmaterial erstellen"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: /usr/bin/wg genkey | tee client_private.key | wg pubkey | tee client_public.key 
    args:
      chdir: /etc/wireguard/
      creates: client_private.key  
 
  - name: "*wireguard* : Zugriffsrechte des Private Keys anpassen"
    # https://docs.ansible.com/ansible/latest/modules/file_module.html
    file: 
      path: /etc/wireguard/client_private.key
      mode: '0600'
 
  - name: "*wireguard* : Zugriffsrechte des Public Keys anpassen"
    # https://docs.ansible.com/ansible/latest/modules/file_module.html
    file: 
      path: /etc/wireguard/client_public.key
      mode: '0600'
~/ansible/roles/wireguard/tasks/genlinklocal.yml
---
  - name: "*wireguard* : lokale link-local IPv6 Adresse aus dem PUBLIC-Key erzeugen"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: cat /etc/wireguard/client_public.key | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/fe80::02\1:\2ff:fe\3:\4\5/'
    register: wg_node_linklocal
~/ansible/roles/wireguard/tasks/configuration.yml
---
  - name: "*wireguard* : private-key einlesen und in Variable übergeben"
    # https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html
    shell: cat /etc/wireguard/client_private.key
    register: wg_client_privatekey
 
  - name: "*wireguard* : public-key einlesen und in Variable übergeben"
    # https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html
    shell: cat /etc/wireguard/client_public.key
    register: wg_client_publickey
 
  - name: "*wireguard* : Socket ermitteln"
    # https://docs.ansible.com/ansible/latest/collections/ansible/builtin/set_fact_module.html
    set_fact:
      ffmuc_wireguard_port: "{{ item.value }}"
    loop: "{{ lookup('dict', wireguard_ports) }}"
    when: "ffmuc_segment in item.key"
 
  - name: "*wireguard* : link-local des Gateways ermitteln"
    # https://docs.ansible.com/ansible/latest/collections/ansible/builtin/set_fact_module.html
    set_fact:
      ffmuc_wireguard_linklocal: "{{ item.value }}"
    loop: "{{ lookup('dict', gw_linklocal) }}"
    when: "ffmuc_gateway in item.key"
 
  - name: "*wireguard* : publickey des Gateways ermitteln"
    # https://docs.ansible.com/ansible/latest/collections/ansible/builtin/set_fact_module.html
    set_fact:
      ffmuc_wireguard_gwpubkey: "{{ item.value }}"
    loop: "{{ lookup('dict', gw_publickey) }}"
    when: "ffmuc_gateway in item.key"
 
  - name: "*wireguard* : Konfigurationsdatei des wireguard-Tunnels erzeugen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template:
      src: templates/uplink.j2
      dest: /etc/wireguard/wg-uplink.conf
~/ansible/roles/wireguard/tasks/brokerinform.yml
---
  - name: "*wireguard* : systemd unit file für broker -Information anlegen"    
     # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template:
      src: templates/broker.j2
      dest: /etc/systemd/system/broker.service
 
  - name: "*wireguard* : Service broker starten beim Booten starten"
    # https://docs.ansible.com/ansible/latest/modules/systemd_module.html
    systemd:
      name: broker
      daemon_reload: yes
      state: started
      enabled: yes
~/ansible/roles/wireguard/tasks/wireguardstart.yml
---
  - name: "*wireguard* : Service wireguard via systemd startem"
    # https://docs.ansible.com/ansible/latest/modules/systemd_module.html
    systemd:
      name: wg-quick@wg-uplink
      daemon_reload: yes
      state: started
      enabled: yes
~/ansible/roles/wireguard/tasks/checkup.yml
---
  - name: "*wireguard* : lokale link-local IPv6 Adresse aus dem PUBLIC-Key erzeugen"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: cat /etc/wireguard/client_public.key | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/fe80::02\1:\2ff:fe\3:\4\5/'
    register: wg_node_linklocal 
 
  - name: "*wireguard* : checkupscript zum Testen der wireguard-Verbindung anlegen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template:
      src: templates/checkup.j2
      dest: /usr/local/bin/checkup
 
  - name: "*wireguard* : Ausführungsrechte des Bash-Scripts anpassen"
    # https://docs.ansible.com/ansible/latest/modules/file_module.html
    file:
      path: /usr/local/bin/checkup
      mode: '0740'
 
  - name: "*wireguard* : crontab für minütlichen checkup der wireguard-Verbindung anlegen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template:
      src: templates/crontab.j2
      dest: /etc/crontab
 
Templates
~/ansible/roles/wireguard/templates/broker.j2
# Django : 2020-12-07
[Unit]
# see man systemd.unit
Description=Inform tunnel about our wireguard-public key
Documentation=https://wiki.mailserver.guru/doku.php/centos:ansible:ffmuc-rpb4-ol
Bevore=wg-quick.target
 
[Service]
# see man systemd.service, systemd.exec
ExecStart=/usr/bin/wget -q -O- --post-data='{"domain":"ffmuc_{{ ffmuc_segment }}","public_key":"{{ wg_client_publickey.stdout }}"}' http://broker.ffmuc.net/api/v1/wg/key/exchange
StandardOutput=syslog
StandardError=syslog
 
[Install]
WantedBy=default.target
~/ansible/roles/wireguard/templates/checkup.j2
#!/bin/bash
 
# Check connectivity to supernode
HTTP_STATUS_CODE=(`curl --silent --interface wg-uplink --get --ipv6 --connect-timeout 5 --write-out '%{http_code}' --output /dev/null 'http://[{{ ffmuc_wireguard_linklocal }}]:80'`)
if [ ${HTTP_STATUS_CODE} != "200" ]; then
        logger -t checkuplink "curl --silent --interface wg-uplink --get --ipv6 --connect-timeout 5 --write-out '%{http_code}' --output /dev/null 'http://[{{ ffmuc_wireguard_linklocal }}]:80' faild with HTTP-errorcode: ${HTTP_STATUS_CODE}"
        logger -t checkuplink "... better we restart the wireguar-tunnel!"
        ip link set nomaster bat-{{ ffmuc_segment }} dev vxlan-mesh &> /dev/null
        ip link del dev mesh-vpn &> /dev/null
        ip link del wg-uplink &> /dev/null
        systemctl stop wg-quick@wg-uplink
        systemctl restart networking
        logger -t checkuplink "Sending public-key to the broker."
        /usr/bin/wget -q -O- --post-data='{"domain":"ffmuc_{{ ffmuc_segment }}","public_key":"{{ wg_client_publickey.stdout }}"}' http://broker.ffmuc.net/api/v1/wg/key/exchange
        logger -t checkuplink "Starting wireguard-daemon."
        systemctl start wg-quick@wg-uplink
        logger -t checkuplink "Starting vxlan-meshing."
        vxlan
else
        #logger -t checkuplink "wiregurad-tunnel is up an running : HTTP-statuscode: ${HTTP_STATUS_CODE}"
fi
~/ansible/roles/wireguard/templates/crontab.j2
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
 
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 
# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17 *	* * *	root    cd / && run-parts --report /etc/cron.hourly
25 6	* * *	root	test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6	* * 7	root	test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6	1 * *	root	test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
 
# check wireguard-connection
* * * * *	root	/usr/local/bin/checkup 2>&1 /dev/null
~/ansible/roles/wireguard/templates/uplink.j2
[Interface]
PrivateKey = {{ wg_client_privatekey.stdout }}
Address = {{ wg_node_linklocal.stdout }}
 
[Peer]
PublicKey = {{ ffmuc_wireguard_gwpubkey }}
AllowedIPs = {{ ffmuc_wireguard_linklocal }}
Endpoint = {{ ffmuc_gateway }}.ext.ffmuc.net:{{ ffmuc_wireguard_port }}
PersistentKeepalive = 25

Rolle "vxlan"

~/ansible/roles/vxlan/tasks/main.yml
--- # Installation und Konfiguration von VXLAN
- include: configure.yml                # VXLAN Konfigurieren
- include: vxlanstart.yml               # Aktivierung des wireguard client-daemon
Tasks
~/ansible/roles/vxlan/tasks/configure.yml
  - name: "*VXLAN* : Paketfilter anpassen - Eingehenden VXLAN Verkehr auf dem Mesh-Interface erlauben"
    # https://docs.ansible.com/ansible/latest/modules/commans_module.html
    command: ip6tables -I INPUT 1 -i wg-uplink -m udp -p udp --dport 8472 -j ACCEPT 
 
  - name: "*VXLAN* : VXLAN-ID des gewählten Segments ermitteln"
    # https://docs.ansible.com/ansible/latest/collections/ansible/builtin/set_fact_module.html
    set_fact:
      ffmuc_vxlan_id: "{{ item.value }}"
    loop: "{{ lookup('dict', gw_vxlan_ids) }}"
    when: "ffmuc_segment in item.key"
 
  - name: "*VXLAN* : link-local des Gateways ermitteln"
    # https://docs.ansible.com/ansible/latest/collections/ansible/builtin/set_fact_module.html
    set_fact:
      ffmuc_wireguard_linklocal: "{{ item.value }}"
    loop: "{{ lookup('dict', gw_linklocal) }}"
    when: "ffmuc_gateway in item.key"
 
  - name: "*VXLAN* : lokale link-local IPv6 Adresse aus dem PUBLIC-Key erzeugen"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: cat /etc/wireguard/client_public.key | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/fe80::02\1:\2ff:fe\3:\4\5/'
    register: wg_node_linklocal
 
  - name: "*VXLAN* : Startupdatei für VXLAN kopieren"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template:
      src: templates/vxlan-init.j2
      dest: /usr/local/bin/vxlan
 
  - name: "*VXLAN* : Ausführungsrechte des Bash-Scripts anpassen"
    # https://docs.ansible.com/ansible/latest/modules/file_module.html
    file:
      path: /usr/local/bin/vxlan
      mode: '0740'
~/ansible/roles/vxlan/tasks/vxlanstart.yml
---
  - name: "*VXLAN* : systemd-unitfile anlegen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template:
      src: templates/systemd-service-file.j2
      dest: /etc/systemd/system/vxlan.service
 
  - name: "*VXLAN* : Neues Unitfile dem systemd bekannt geben"
    # https://docs.ansible.com/ansible/latest/modules/systemd_module.html
    systemd:
      daemon_reexec: yes
 
  - name: "*VXLAN* : Service vxlan via systemd starten"
    # https://docs.ansible.com/ansible/latest/modules/systemd_module.html
    systemd:
      name: vxlan.service
      daemon_reload: yes
      state: started
      enabled: yes
Templates
~/ansible/roles/vxlan/templates/systemd-service-file.j2
[Unit]
# see man systemd.unit
Description=Bringing up VXLAN Interface
Documentation=https://wiki.mailserver.guru/doku.php/centos:ansible:ffmuc-rpb4-ol
After=wg-quick@wg-uplink.service
 
[Service]
# see man systemd.service, systemd.exec
Type=oneshot
ExecStart=/usr/local/bin/vxlan
StandardOutput=syslog
StandardError=syslog
 
[Install]
WantedBy=multi-user.target
~/ansible/roles/vxlan/templates/vxlan-init.j2
#!/bin/bash
 
# Bring up VXLAN
ip link add mesh-vpn type vxlan id {{ ffmuc_vxlan_id }} local {{ wg_node_linklocal.stdout }} remote {{ ffmuc_wireguard_linklocal }} dstport 8472 dev wg-uplink
ip link set up dev mesh-vpn
 
# Bind mesh-vpn to BATMAN-Device
/usr/sbin/batctl meshif bat-{{ ffmuc_segment }} if add mesh-vpn
 
# If we have a BATMAN_V env we need to correct the throughput value now
/usr/sbin/batctl hardif mesh-vpn throughput_override 10000

Rolle "ext-respondd"

Tasks
~/ansible/roles/ext-respondd/tasks/main.yml
--- # Installation und Konfiguration des ext-respondd (Statistiken für https://map.ffmuc.net)
- include: gitinstall.yml               # Installation der Pakete git und python3-netifaces 
- include: gitclone.yml                 # Repo ext-respondd klonen 
- include: copyconfig.yml               # Systemd Startdatei für respondd kopieren
- include: aliasgenerate.yml            # Erstellen der resondd Konfigurationsdatei alias.json 
- include: configgenerate.yml           # Erstellen der resondd Konfigurationsdatei config.json
- include: servicestartup.yml           # Service ext-respondd beim Booten starten
~/ansible/roles/ext-respondd/tasks/aliasgenerate.yml
---
  - name: "Erstellen der resondd Konfigurationsdatei alias.json"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/ext-respondd_alias.json.j2
      dest: /opt/ext-respondd/alias.json
~/ansible/roles/ext-respondd/tasks/configgenerate.yml
---
  - name: "Erstellen der resondd Konfigurationsdatei config.json"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/ext-respondd_config.json.j2
      dest: /opt/ext-respondd/config.json
~/ansible/roles/ext-respondd/tasks/copyconfig.yml
---
  - name: "Systemd Startdatei für respondd kopieren"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: 
      cmd: cp /opt/ext-respondd/ext-respondd.service.example /etc/systemd/system/ext-respondd.service
~/ansible/roles/ext-respondd/tasks/gitclone.yml
---
  - name: "Repo ext-respondd klonen"
    # https://docs.ansible.com/ansible/latest/modules/git_module.html
    git:
      repo: https://github.com/freifunkMUC/ext-respondd
      dest: /opt/ext-respondd/
~/ansible/roles/ext-respondd/tasks/gitinstall.yml
---
  - name: "Installation der Pakete git und python3-netifaces"
    # https://docs.ansible.com/ansible/latest/modules/apt_module.html
    apt: 
      update_cache: yes
      pkg:
        - git
        - python3-netifaces
      state: present
~/ansible/roles/ext-respondd/tasks/servicestartup.yml
---
  - name: "Service ext-respondd beim Booten starten"
    # https://docs.ansible.com/ansible/latest/modules/systemd_module.html
    systemd:
      name: ext-respondd
      daemon_reload: yes
      state: started
      enabled: yes
Templates
~/ansible/roles/ext-respondd/templates/ext-respondd_alias.json.j2
{
  "nodeinfo": {
    "hostname": "{{ raspberry_hostname }}",
    "hardware": {
      "model": "Raspberry Pi 4B"
    },
    "owner": {
      "contact": "{{ node_contact_address }}"
    },
    "system": {
      "site_code": "ffmuc_{{ ffmuc_segment }}",
      "role": "client"
    },
    "location": {
    "latitude": {{ raspberry_latitude }},
    "longitude": {{ raspberry_longitude }}
    }
  },
  "firstseen": "2019-08-14T12:34:56"
}
~/ansible/roles/ext-respondd/templates/ext-respondd_config.json.j2
{
  "batman": "bat-{{ ffmuc_segment }}",
  "bridge": "br-{{ ffmuc_segment }}",
  "mesh-vpn": [ "fastd-{{ ffmuc_segment }}" ],
  "wan": "eth0",
  "rate_limit": 30,
  "rate_limit_burst": 10
}

Rolle "hostapd"

Tasks
~/ansible/roles/hostapd/tasks/main.yml
--- # Installation und Konfiguration des hostap Treibers für den WiFi-Support
- include: install.yml                  # Paket hostapd für WLAN installieren
- include: configure.yml                # hostapd konfigurieren
- include: genconfig.yml                # hostapd Konfigurationsdatei anlegen
- include: wlanbridging.yml             # wlan0 in Bridge packen
- include: servicestartup.yml           # Service hostapd beim Booten und jetzt starten und das Laden der Unit Datei vom Service hostapd ermöglichen
~/ansible/roles/hostapd/tasks/configure.yml
---
  - name: "hostapd konfigurieren"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: echo 'DAEMON_OPTS="-d"' >> /etc/default/hostapd
    when: ( raspberry_wifi == "ja" )
~/ansible/roles/hostapd/tasks/genconfig.yml
---
  - name: "hostapd Konfigurationsdatei anlegen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/hostapd.j2
      dest: /etc/hostapd/hostapd.conf
    when: ( raspberry_wifi == "ja" )
~/ansible/roles/hostapd/tasks/install.yml
---
  - name: "Paket hostapd für WLAN installieren"
    # https://docs.ansible.com/ansible/latest/modules/apt_module.html
    apt:
      update_cache: yes
      pkg:
        - hostapd
      state: present
    when: ( raspberry_wifi == "ja" )
~/ansible/roles/hostapd/tasks/servicestartup.yml
---
  - name: "Service hostapd beim Booten und jetzt starten und das Laden der Unit Datei vom Service hostapd ermöglichen"
    # https://docs.ansible.com/ansible/latest/modules/systemd_module.html
    systemd:
      name: hostapd
      enabled: yes
      masked: no
      state: started
    when: ( raspberry_wifi == "ja" )
~/ansible/roles/hostapd/tasks/wlanbridging.yml
---
  - name: "wlan0 in Bridge packen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/rclocal_wifi.j2
      dest: /etc/rc.local
    when: ( raspberry_wifi == "ja" )
Templates
~/ansible/roles/hostapd/templates/hostapd.j2
ssid=muenchen.freifunk.net/{{ ffmuc_segment }}
 
country_code=US
 
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
~/ansible/roles/hostapd/templates/rclocal_wifi.j2
#!/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-{{ ffmuc_segment }} wlan0
exit 0

Rolle "client-mesh"

Tasks
~/ansible/roles/client-mesh/tasks/main.yml
--- # Grundkonfiguration von Client und/oder Meshing (V)LANs
- include: clientohnemesh.yml           # Konfiguration des Client-VLAN ohne Mesh-Netz
- include: getvxlanid.yml               # vxlan_id für ausgewähltes Segment ermitteln
- include: meshohneclient.yml           # Konfiguration des Mesh-VLAN ohne Client-VLAN
- include: meshundclient.yml            # Konfiguration von Mesh- und Client-VLAN
- include: batmanohnewifi.yml           # Konfiguration des bevorzugte Meshingpoint in BATMAN_V ohne Wifi-Nutzung
- include: batmanmitwifi.yml            # Konfiguration des bevorzugte Meshingpoint in BATMAN_V mit Wifi-Nutzung
~/ansible/roles/client-mesh/tasks/batmanmitwifi.yml
---
  - name: "Konfiguration des bevorzugte Meshingpoint in BATMAN_V mit Wifi-Nutzung"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/rclocal_both.j2
      dest: /etc/rc.local
    when: ( raspberry_meshvlan|length > 0 ) and ( raspberry_wifi == "ja" )
~/ansible/roles/client-mesh/tasks/batmanohnewifi.yml
---
  - name: "Konfiguration des bevorzugte Meshingpoint in BATMAN_V ohne Wifi-Nutzung"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/rclocal_vxlan.j2
      dest: /etc/rc.local
    when: ( raspberry_meshvlan|length > 0 ) and ( raspberry_wifi != "ja" )
~/ansible/roles/client-mesh/tasks/clientohnemesh.yml
django@Djangos-ThinkPad-X230:~$ cat ~/ansible/roles/client-mesh/tasks/clientohnemesh.yml 
---
  - name: "Konfiguration des Client-VLAN ohne Mesh-Netz"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/interfaces_client_ohne_mesh.j2
      dest: /etc/network/interfaces
    when: ( raspberry_clientvlan|length > 0 ) and ( raspberry_meshvlan|length == 0 )
~/ansible/roles/client-mesh/tasks/getvxlanid.yml
---
  - name: "vxlan_id für ausgewähltes Segment ermitteln"
    # https://docs.ansible.com/ansible/latest/modules/set_fact_module.html
    set_fact:
      ffmuc_vxlan_id: "{{ item.value }}"
    loop: "{{ lookup('dict', vxlan_ids) }}"
    when: "ffmuc_segment in item.key"
~/ansible/roles/client-mesh/tasks/meshohneclient.yml
---
  - name: "Konfiguration des Mesh-VLAN ohne Client-VLAN"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/interfaces_mesh_ohne_client.j2
      dest: /etc/network/interfaces
    when: ( raspberry_clientvlan|length == 0 ) and ( raspberry_meshvlan|length > 0 )
~/ansible/roles/client-mesh/tasks/meshundclient.yml
---
  - name: "Konfiguration von Mesh- und Client-VLAN"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/interfaces_mesh_mit_client.j2
      dest: /etc/network/interfaces
    when: ( raspberry_clientvlan|length > 0 ) and ( raspberry_meshvlan|length > 0 )
Templates
~/ansible/roles/client-mesh/templates/interfaces_client_ohne_mesh.j2
# 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:
# source-directory /etc/network/interfaces.d
 
auto eth0
iface eth0 inet dhcp
 
auto eth0.{{ raspberry_clientvlan }}
iface eth0.{{ raspberry_clientvlan }} inet manual
 
auto br-{{ ffmuc_segment }}
iface br-{{ ffmuc_segment }} inet dhcp
        bridge-ports bat-{{ ffmuc_segment }} eth0.{{ raspberry_clientvlan }}
        pre-up /usr/sbin/batctl ra BATMAN_V
        pre-up /sbin/ip link add dummy-{{ ffmuc_segment }} 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-{{ ffmuc_segment }}
        pre-up /sbin/ip link set dummy-{{ ffmuc_segment }} up
        pre-up /usr/sbin/batctl meshif bat-{{ ffmuc_segment }} if add dummy-{{ ffmuc_segment }}
        pre-up /sbin/ip link set bat-{{ ffmuc_segment }} up
        pre-up /usr/sbin/batctl meshif bat-{{ ffmuc_segment }} 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-{{ ffmuc_segment }}
        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-{{ ffmuc_segment }}
~/ansible/roles/client-mesh/templates/interfaces_mesh_mit_client.j2
# 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:
# source-directory /etc/network/interfaces.d
 
auto eth0
iface eth0 inet dhcp
 
auto eth0.{{ raspberry_meshvlan }}
iface eth0.{{ raspberry_meshvlan }} inet manual
        pre-up /sbin/ip link add vxlan-mesh type vxlan id {{ ffmuc_vxlan_id }} group ff02::15c dstport 4789 port 32768 61000 no udpcsum udp6zerocsumtx udp6zerocsumrx dev eth0.{{ raspberry_meshvlan }} || true
        up /sbin/ip link set vxlan-mesh up
        post-up /usr/sbin/batctl ra BATMAN_V
        post-up /usr/sbin/batctl meshif bat-{{ ffmuc_segment }} if add vxlan-mesh
        down ip link set vxlan-mesh down
        post-down ip link del vxlan-mesh || true
 
auto eth0.{{ raspberry_clientvlan }}
iface eth0.{{ raspberry_clientvlan }} inet manual
 
auto br-{{ ffmuc_segment }}
iface br-{{ ffmuc_segment }} inet dhcp
        bridge-ports bat-{{ ffmuc_segment }} eth0.{{ raspberry_clientvlan }}
        pre-up /usr/sbin/batctl ra BATMAN_V
        pre-up /sbin/ip link add dummy-{{ ffmuc_segment }} 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-{{ ffmuc_segment }}
        pre-up /sbin/ip link set dummy-{{ ffmuc_segment }} up
        pre-up /usr/sbin/batctl meshif bat-{{ ffmuc_segment }} if add dummy-{{ ffmuc_segment }}
        pre-up /sbin/ip link set bat-{{ ffmuc_segment }} up
        pre-up /usr/sbin/batctl meshif bat-{{ ffmuc_segment }} 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-{{ ffmuc_segment }}
        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-{{ ffmuc_segment }}
~/ansible/roles/client-mesh/templates/interfaces_mesh_ohne_client.j2
# 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:
# source-directory /etc/network/interfaces.d
 
auto eth0
iface eth0 inet dhcp
 
auto eth0.{{ raspberry_meshvlan }}
iface eth0.{{ raspberry_meshvlan }} inet manual
        pre-up /sbin/ip link add vxlan-mesh type vxlan id {{ ffmuc_vxlan_id }} group ff02::15c dstport 4789 port 32768 61000 no udpcsum udp6zerocsumtx udp6zerocsumrx dev eth0.{{ raspberry_meshvlan }} || true
        up /sbin/ip link set vxlan-mesh up
        post-up /usr/sbin/batctl ra BATMAN_V
        post-up /usr/sbin/batctl meshif bat-{{ ffmuc_segment }} if add vxlan-mesh
        down ip link set vxlan-mesh down
        post-down ip link del vxlan-mesh || true
 
auto br-{{ ffmuc_segment }}
iface br-{{ ffmuc_segment }} inet dhcp
        bridge-ports bat-{{ ffmuc_segment }}
        pre-up /usr/sbin/batctl ra BATMAN_V
        pre-up /sbin/ip link add dummy-{{ ffmuc_segment }} 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-{{ ffmuc_segment }}
        pre-up /sbin/ip link set dummy-{{ ffmuc_segment }} up
        pre-up /usr/sbin/batctl meshif bat-{{ ffmuc_segment }} if add dummy-{{ ffmuc_segment }}
        pre-up /sbin/ip link set bat-{{ ffmuc_segment }} up
        pre-up /usr/sbin/batctl meshif bat-{{ ffmuc_segment }} 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-{{ ffmuc_segment }}
        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-{{ ffmuc_segment }}
~/ansible/roles/client-mesh/templates/rclocal_both.j2
#!/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-{{ ffmuc_segment }} wlan0
/usr/sbin/batctl hardif mesh-vpn throughput_override 10000
exit 0
~/ansible/roles/client-mesh/templates/rclocal_vxlan.j2
#!/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
/usr/sbin/batctl hardif mesh-vpn throughput_override 10000
exit 0

Rolle "oled"

Tasks
~/ansible/roles/oled/tasks/main.yml
--- # Konfiguration eines OLEDisplays sofern eines am Respberry 4B verbaut ist
- include: i2c-bcm2708.yml              # Für OLED-Konfiguration i2c-bcm2708 in /etc/modules eintragen
- include: i2c-dev.yml                  # Für OLED-Konfiguration i2c-dev in /etc/modules eintragen
- include: packages.yml                 # Installation der für das OLED benötigten Pakete
- include: i2c_arm.yml                  # Laden des Kernelmodul i2c_arm beim Booten veranlassen
- include: reboot.yml                   # Reboot nach Konfigurationsänderung
- include: adafruitclone.yml            # Repo Adafruit_Python_SSD1306 klonen
- include: adafruitconfig.yml           # Für OLED-Konfiguration Adafruit_Python_SSD1306 installieren
- include: scriptclone.yml              # Script zur Anzeige klonen 
- include: scriptconfig.yml             # Script zur Bandbreitenauslastung anpassen 
- include: scriptstart.yml              # Startscript für das OLED anlegen 
- include: scriptstartup.yml            # Service oled-bandwidth beim Booten starten
~/ansible/roles/oled/tasks/adafruitclone.yml
---
  - name: "Repo Adafruit_Python_SSD1306 klonen"
    # https://docs.ansible.com/ansible/latest/modules/git_module.html
    git:
      repo: https://github.com/adafruit/Adafruit_Python_SSD1306.git
      dest: /usr/local/src/Adafruit_Python_SSD1306
    when: ( raspberry_oled == "ja" )
~/ansible/roles/oled/tasks/adafruitconfig.yml
---
  - name: "Für OLED-Konfiguration Adafruit_Python_SSD1306 installieren"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: cd /usr/local/src/Adafruit_Python_SSD1306 && python3 setup.py install && pip3 install Adafruit-BBIO
    when: ( raspberry_oled == "ja" )
~/ansible/roles/oled/tasks/i2c_arm.yml
---
  - name: "Laden des Kernelmodul i2c_arm beim Booten veranlassen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/config.j2
      dest: /boot/config.txt
    when: ( raspberry_oled == "ja" )
~/ansible/roles/oled/tasks/i2c-bcm2708.yml
---
  - name: "Für OLED-Konfiguration i2c-bcm2708 in /etc/modules eintragen"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: echo i2c-bcm2708 >> /etc/modules
    when: ( raspberry_oled == "ja" )
~/ansible/roles/oled/tasks/i2c-dev.yml
---
  - name: "Für OLED-Konfiguration i2c-dev in /etc/modules eintragen"
    # https://docs.ansible.com/ansible/latest/modules/shell_module.html
    shell: echo i2c-dev >> /etc/modules
    when: ( raspberry_oled == "ja" )
~/ansible/roles/oled/tasks/packages.yml
---
  - name: "Installation der für das OLED benötigten Pakete"
    # https://docs.ansible.com/ansible/latest/modules/apt_module.html
    apt:
      update_cache: yes
      pkg:
        - python3-dev
        - python3-smbus
        - i2c-tools
        - python3-pil
        - python3-pip
        - python3-setuptools
        - python3-rpi.gpio
        - git
        - fonts-freefont-ttf
      state: present
    when: ( raspberry_oled == "ja" )
~/ansible/roles/oled/tasks/reboot.yml
---
  - name: "Reboot nach Konfigurationsänderung"
    # https://docs.ansible.com/ansible/latest/modules/reboot_module.html
    reboot:
    when: ( raspberry_oled == "ja" )
~/ansible/roles/oled/tasks/scriptclone.yml
---
  - name: "Script zur Anzeige klonen"
    # https://docs.ansible.com/ansible/latest/modules/git_module.html
    git:
      repo: https://github.com/awlx/raspberry-oled-bandwidth
      dest: /usr/local/src/raspberry-oled-bandwidth
      force: yes
    when: ( raspberry_oled == "ja" )
~/ansible/roles/oled/tasks/scriptconfig.yml
---
  - name: "Script zur Bandbreitenauslastung anpassen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/bandwidth.j2
      dest: /usr/local/src/raspberry-oled-bandwidth/bandwidth.py
    when: ( raspberry_oled == "ja" )
~/ansible/roles/oled/tasks/scriptstart.yml
---
  - name: "Startscript für das OLED anlegen"
    # https://docs.ansible.com/ansible/latest/modules/template_module.html
    template: 
      src: templates/oled-bandwidth.j2
      dest: /etc/systemd/system/oled-bandwidth.service
    when: ( raspberry_oled == "ja" )
~/ansible/roles/oled/tasks/scriptstartup.yml
---
  - name: "Service oled-bandwidth beim Booten starten"
    # https://docs.ansible.com/ansible/latest/modules/systemd_module.html
    systemd:
      name: oled-bandwidth
      daemon_reload: yes
      state: started
      enabled: yes
    when: ( raspberry_oled == "ja" )
Templates
~/ansible/roles/oled/templates/bandwidth.j2
# 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 = 'mesh-vpn'
batman = 'bat-{{ ffmuc_segment }}'
primary_mac = '{{ ansible_eth0.macaddress }}'
 
# 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 = 'P9_15'
 
# 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 meshif " + 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()
~/ansible/roles/oled/templates/config.j2
# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details
 
# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1
 
# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
#disable_overscan=1
 
# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16
 
# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720
 
# uncomment if hdmi display is not detected and composite is being output
#hdmi_force_hotplug=1
 
# uncomment to force a specific HDMI mode (this will force VGA)
#hdmi_group=1
#hdmi_mode=1
 
# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2
 
# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4
 
# uncomment for composite PAL
#sdtv_mode=2
 
#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800
 
# Uncomment some or all of these to enable the optional hardware interfaces
# Django : 2019-09-11
# default: # dtparam=i2c_arm=on
dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on
 
# Uncomment this to enable the lirc-rpi module
#dtoverlay=lirc-rpi
 
# Additional overlays and parameters are documented /boot/overlays/README
 
# Enable audio (loads snd_bcm2835)
dtparam=audio=on
 
[pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack
dtoverlay=vc4-fkms-v3d
max_framebuffers=2
 
[all]
#dtoverlay=vc4-fkms-v3d
~/ansible/roles/oled/templates/oled-bandwidth.j2
# Django : 2019-09-11
[Unit]
# see man systemd.unit
Description=Starting OLED-Trafic output
Documentation=https://wiki.mailserver.guru/doku.php/centos:ansible:ffmuc-rpb4-ol
After=network.target
 
[Service]
# see man systemd.service, systemd.exec
ExecStart=/usr/bin/python3 /usr/local/src/raspberry-oled-bandwidth/bandwidth.py
StandardOutput=syslog
StandardError=syslog
 
[Install]
WantedBy=default.target

Rolle "final"

Tasks
~/ansible/roles/final/tasks/main.yml
--- # Reboot nach Abschluss der Konfiguration unseres Offloaders
- include: reboot.yml                   # /etc/hosts anpassen
... #YAML Ende Syntax
~/ansible/roles/final/tasks/reboot.yml
---
  - name: "Reboot nach Abschluss der Konfiguration unseres Offloaders"
    # https://docs.ansible.com/ansible/latest/modules/reboot_module.html
    reboot:

Nachdem es aktuell7) noch kein fertiges Gluon Image für das Raspberry PI 4B gibt, holen wir uns nun das aktuelle Raspberry Pi OS (früher unter dem Namen Raspbian bekannt) auf unseren Rechner. Dies hat mitunter auch noch den Charme, dass wir bei Bedarf alle normalen Anwendungen wie Webserver, Chatserver oder z.B. den Unifi-Controller einfach installieren können.

Eine Anleitung zur manuellen Installation findet man auf der offiziellen Raspbian Seite.

 $ wget https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2020-08-24/2020-08-20-raspios-buster-armhf-lite.zip

Bevor wir nun das Archiv entpacken überprüfen wir noch die Integrität der heruntergeladenen Datei. Hierzu berechnen wir erst einmal die SHA256-Prüfsumme der Datei raspbian_lite_latest.

 $ sha256sum raspbian_lite_latest
4522df4a29f9aac4b0166fbfee9f599dab55a997c855702bfe35329c13334668  2020-08-20-raspios-buster-armhf-lite.zip

Die Zeichenfolge überprüfen wir nun mit den Angaben auf der Seite: https://www.raspberrypi.org/downloads/raspbian/ Bild: Bildschirmhardcopy der Seite www.raspberrypi.org/software/operating-systems (Stand: 16.02.2020)

Da sich beide SHA-Werte nicht unterscheiden können wir das herunter geladene ZIP-Archiv nun entpacken.

 $ unzip 2020-08-20-raspios-buster-armhf-lite.zip
Archive:  2020-08-20-raspios-buster-armhf-lite.zip
  inflating: 2020-08-20-raspios-buster-armhf-lite.img

Nun können wir das Image auf die MicroSD Karte, die wir später in den Raspberry 4B stecken kopieren. Wir werfen also am besten einmal einen Blick in das syslog unseres Arbeitsrechners und erkennen so das Device unserer Speicherkarte.

 # tail -f /var/log/messages

bzw.

 $ sudo tail -f /var/log/syslog
Sep  5 21:10:57 Djangos-ThinkPad-X230 kernel: [12795.867603] mmc0: new high speed SDHC card at address aaaa
Sep  5 21:10:57 Djangos-ThinkPad-X230 kernel: [12795.868313] mmcblk0: mmc0:aaaa SC16G 14.8 GiB 
Sep  5 21:10:57 Djangos-ThinkPad-X230 kernel: [12795.871017]  mmcblk0: p1 p2
Sep  5 21:10:58 Djangos-ThinkPad-X230 kernel: [12796.199093] FAT-fs (mmcblk0p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
Sep  5 21:10:58 Djangos-ThinkPad-X230 systemd[1]: Finished Clean the /media/django/boot mount point.
Sep  5 21:10:58 Djangos-ThinkPad-X230 udisksd[976]: Mounted /dev/mmcblk0p1 at /media/django/boot on behalf of uid 1001
Sep  5 21:10:58 Djangos-ThinkPad-X230 kernel: [12796.302402] EXT4-fs (mmcblk0p2): recovery complete
Sep  5 21:10:58 Djangos-ThinkPad-X230 kernel: [12796.303545] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
Sep  5 21:10:58 Djangos-ThinkPad-X230 systemd[1]: Finished Clean the /media/django/rootfs mount point.
Sep  5 21:10:58 Djangos-ThinkPad-X230 udisksd[976]: Mounted /dev/mmcblk0p2 at /media/django/rootfs on behalf of uid 1001
Sep  5 21:11:09 Djangos-ThinkPad-X230 gnome-terminal-[8119]: g_menu_insert_item: assertion 'G_IS_MENU_ITEM (item)' failed

In dem gezeigtem Fall handelt es sich also um die Gerätedatei /dev/mmcblk0. Wir wissen also wie wir nun die zuvor heruntergeladene Debian Buster Image-Datei auf die MicroSD-Karte kopieren müssen. In der Regel hat der „normale Nutzer“ keine Rechte um diese Gerätedatei anzusprechen, wir müssen also als Benutzer root oder mir den Rechten des Benutzers root die Gerätedatei /dev/mmcblk0 in diesem Konfigurationsbeispiel ansprechen.

 # dd if=~/2020-08-20-raspios-buster-armhf-lite.img of=/dev/mmcblk0  bs=4M status=progress conv=fsync

bzw.

 $ sudo dd if=/home/django/Freifunk/2020-08-20-raspios-buster-armhf-lite.img of=/dev/mmcblk0 bs=4M status=progress conv=fsync

Da wir später weder Tastatur noch Monitor an unseren Raspberry 4B anstecken wollen, diesen demnach im headless-Mode betreiben wollen und werden, legen wir noch eine Datei /boot/ssh auf der SD-Karte ab. Nach dem erneuten Anstecken der MicroSD-Karte wir der Speicher in der Regel im Verzeichnis /run/media/ oder auch /media/gemountet. Zum Anlagen der betreffenden Datei ssh in dem Verzeichnis reicht also folgender Aufruf, bei dem wir den Usernamen natürlich unseren Gegebenheiten entsprechend anpassen.:

 # touch /run/media/django/boot/ssh

bzw.

 $ touch /media/django/boot/ssh

Anschließend können wir nach einem unmounten des Gerätes /dev/sdb die Micro-SD-Karte in den Kartenslot des Raspberry 4B stecken und den Kleinstcomputer mit dem Netzwerk sowie dem zugehörigen Netzteil verbinden und starten.

Der Benutzername lautet piund das Passwort raspberry. Das Passwort dieses Nutzers ändern wir nun als erstes ab, da sonst die Gefahr besteht, dass Fremde sich unseres Offloaders bemächtigen!

Wir ändern also das Default-Passwort gleich mal ab und packen auch unseren SSH-Public-key auf den Raspberry 4B. Da wir die IP-Adresse, die unser Raspberry vom DHCP-Server zugewiesen bekommt in unserer SSH-Client-Konfigurationsdatei bereits hinterlegt haben, können wir nun den RaspBerry 4B direkt über den definierten Namen raspberry-ansible ansprechen.

 $ ssh -l pi raspberry-ansible -o IdentitiesOnly=yes "passwd" && \
       ssh-copy-id -i ~/.ssh/id_ed25519_ffmuc.pub -o IdentitiesOnly=yes pi@raspberry-ansible

Alternativ dazu müssten wir den Raspberry 4B über die IP-Adresse ansprechen, die dieser zugewiesen bekommt. In dem folgenden Beispiel wäre das die IP-Adresse: 192.168.0.25:

 $ ssh -l pi 192.168.0.25 -o IdentitiesOnly=yes "passwd" && \
       ssh-copy-id -i ~/.ssh/id_ed25519_ffmuc.pub -o IdentitiesOnly=yes pi@192.168.0.25

In dem folgenden Konfigurationsbeispiel vergeben wir für den Benutzer pi das Passwort gECzebzn7GYSLvXueECAxeGm7l7. Beim Ändern des bestehenden Passwortes müssen wir einmal das Default-Passwort raspberry eingeben und dann 2x das neue gECzebzn7GYSLvXueECAxeGm7l7. Beim Kopieren des Public-Keys müssen wir dann einmalig das neue geänderte Passwort gECzebzn7GYSLvXueECAxeGm7l7 verwenden.

The authenticity of host '10.0.10.29 (10.0.10.29)' can't be established.
ECDSA key fingerprint is SHA256:vXhdvud24tyTUtOan4XeTZ7GzxZDQn9Rj0mxuhimkH4.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.0.10.29' (ECDSA) to the list of known hosts.
pi@10.0.10.29's password: 
Current password: raspberry
New password: gECzebzn7GYSLvXueECAxeGm7l7
Retype new password: gECzebzn7GYSLvXueECAxeGm7l7
passwd: password updated successfully
Changing password for pi.
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/django/.ssh/id_ed25519_freifunk.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
pi@10.0.10.29's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh -o 'IdentitiesOnly=yes' 'pi@raspberry-ansible'"
and check to make sure that only the key(s) you wanted were added.
 $ ssh raspberry-ansible 

Linux raspberrypi 5.4.51-v7l+ #1333 SMP Mon Aug 10 16:51:40 BST 2020 armv7l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/STERNCHEN/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

Wi-Fi is currently blocked by rfkill.
Use raspi-config to set the country before use.

pi@raspberrypi:~ $ 

Beim Abarbeiten des ansible-playbook werden zur Konfiguration des Offloaders und dessen Komponenten/Dienste folgende Parameter benötigt:

  • Batman-Release (Version) der zum Einsatz kommen soll.
  • Segment/Domäne in dem der Offloader betrieben werden soll
  • Angaben zur Freifunk Karte zur Darstellung
    • Hostname des Offloaders
    • Kontakt-Adresse des Node-Betreibers
    • Geographische Breitengrad des Raspberry Offloaders
    • Geographische Längengrad des Raspberry Offloaders
  • Funktionen, die der Raspberry Offloader noch ausführen soll:
    • Soll der Raspberry Offloader ein WLAN ausstrahlen (SSID leitet sich vom Segment-Namen ab)?
    • Soll der Raspberry Offloader ein Client-VLAN zur Verfügung stellen, wenn ja wie lautet die VLAN-ID?
    • Soll der Raspberry Offloader ein Mesh-VLAN zur Verfügung stellen, wenn ja wie lautet die VLAN-ID?
  • Ist an dem Raspberry ein OLE-Display von AZDelivery verbaut/angeschlossen?

wireguard-offloader.yml

In dem tar.gz-Archiv des Playbooks ist seit Version v4 8) folgendes ansible-playbooks enthalten: wireguard-offloader.yml.yml

Hier werden die zur Konfiguration benötigten Parameter nicht beim Aufruf des Playbooks abgefragt, sondern in zugehörigen Inventory-Datei hinterlegt. Das ist im ersten Schritt für den ungeübten Ansible-Nutzer zwar augenscheinlich aufwändiger, hat aber den Vorteil, dass man die zur Konfiguration benötigten Parameter immer sofort „zur Hand“ hat.

In den Zeilen 55 bis 64 sind diese Parameter entsprechend zu hinterlegen.

 $ vim ~/ansible/inventories/production/hosts.yml +54
 54     batman_adv_version:   "2020.4"
 55     ffmuc_segment:        "muc_ost"
 56     ffmuc_gateway:        "gw04"
 57     raspberry_hostname:   "raspbian-ansible-offloader"
 58     node_contact_address: "https://bit.ly/2VxGoXp"
 59     raspberry_latitude:   "48.239094621"
 60     raspberry_longitude:  "11.558936834"
 61     raspberry_wifi:       "ja"
 62     raspberry_clientvlan: "123"
 63     raspberry_meshvlan:   "456"
 64     raspberry_oled:       "ja"

Playbook Lauf

Nachdem wir die Informationen in dem Ansible-Playbook hinterlegt haben, können wir wie gewohnt das Ansible-Scriptes ausführen.

 $ ansible-playbook ~/ansible/playbooks/wireguard-offloader.yml


PLAY [raspi_offloader.yml] *********************************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************************************
ok: [raspi_offloader]

TASK [basic : Hostname ändern] *****************************************************************************************************************************
changed: [raspi_offloader]

TASK [basic : Template Konfigurationsdatei für /etc/hosts an Ort und Stelle kopieren und Variablen anpassen] ***********************************************
changed: [raspi_offloader]

TASK [basic : Beschreibung des User 'pi' anpassen] *********************************************************************************************************
changed: [raspi_offloader]

TASK [basic : Service rfkill am Raspberry deaktivieren] ****************************************************************************************************
changed: [raspi_offloader]

TASK [basic : Update und Upgrade der APT-Paket] ************************************************************************************************************
[WARNING]: Updating cache and auto-installing missing dependency: python-apt
changed: [raspi_offloader]

TASK [basic : Reboot nach update] **************************************************************************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN Installation* : Download des aktuellen BATMAN Archives] *****************************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN Installation* : Entpacken des BATMAN-Archives] **************************************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN compile* : Installation des Dynamic Kernel Module Support Framework und der Header Files für den Raspberry Pi OS Linux Kernel] ******
changed: [raspi_offloader]

TASK [batman : *BATMAN compile* : Rebuild BATMAN Kernel Header Dateien] ************************************************************************************
fatal: [raspberry-wireguard]: FAILED! => {"changed": false, "cmd": "/usr/bin/make scripts", "msg": "make: *** No rule to make target 'scripts'.  Stop.", "rc": 2, "stderr": "make: *** No rule to make target 'scripts'.  Stop.\n", "stderr_lines": ["make: *** No rule to make target 'scripts'.  Stop."], "stdout": "", "stdout_lines": []}
...ignoring

TASK [batman : *BATMAN compile* : Anlegen der dkms.conf für Dynamic Kernel Module Support] *****************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN compile* : Dynamic Kernel Module Support hinzufügen] ********************************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN compile* : Dynamic Kernel Module bauen] *********************************************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN compile* : BATMAN Dynamic Kernel Module installieren] *******************************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN load-modules* : Laden der BATMAN Dynamic Kernel Module beim Booten sicherstellen] ***************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN load-modules* : dummy Modul laden] **************************************************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN load-modules* : BATMAN-ADV Modul laden] *********************************************************************************************
changed: [raspi_offloader]

TASK [batman : *buster-backport* : PGP-Schlüssel 04EE7237B7D453EC für buster-backports installieren] *******************************************************
changed: [raspi_offloader]

TASK [batman : *buster-backport* : PGP-Schlüssel 648ACFD622F3D138 für buster-backports installieren] *******************************************************
changed: [raspi_offloader]

TASK [batman : *buster-backport* : buster-backports dem System bekannt machen] *****************************************************************************
changed: [raspi_offloader]

TASK [batman : *buster-backport* : APT-Cache aktualisieren] ************************************************************************************************
changed: [raspi_offloader]

TASK [batman : *utils-installation* : Installation der bridge-utils] ***************************************************************************************
changed: [raspi_offloader]

TASK [batman : *utils-installation* : Installation der bridge-utils] ***************************************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN-ADV* : Aktivierung von BATMAN_V] ****************************************************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN-ADV Interfaces* : Konfiguration des Interfaces] *************************************************************************************
changed: [raspi_offloader]

TASK [batman : *BATMAN Installation* : Reboot nach Ende der BATMAN Installationsschritte] ******************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : Installation von wireguard] ************************************************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : Schlüsselmaterial erstellen] ***********************************************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : Zugriffsrechte des Private Keys anpassen] **********************************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard : *wireguard* : Zugriffsrechte des Public Keys anpassen] **********************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard : *wireguard* : lokale link-local IPv6 Adresse aus dem PUBLIC-Key erzeugen] ***************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : private-key einlesen und in Variable übergeben] ****************************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : public-key einlesen und in Variable übergeben] *****************************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : Socket ermitteln] **********************************************************************************************************
skipping: [raspberry-wireguard] => (item={'key': 'muc_cty', 'value': 40002}) 
skipping: [raspberry-wireguard] => (item={'key': 'muc_nord', 'value': 40003})
ok: [raspberry-wireguard] => (item={'key': 'muc_ost', 'value': 40004})
skipping: [raspberry-wireguard] => (item={'key': 'muc_sued', 'value': 40005}) 
skipping: [raspberry-wireguard] => (item={'key': 'muc_west', 'value': 40006}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_nord', 'value': 40007}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_ost', 'value': 40008}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_sued', 'value': 40009}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_west', 'value': 40010}) 
skipping: [raspberry-wireguard] => (item={'key': 'gauting', 'value': 40012}) 
skipping: [raspberry-wireguard] => (item={'key': 'freising', 'value': 40013}) 
skipping: [raspberry-wireguard] => (item={'key': 'welt', 'value': 40011}) 

TASK [wireguard : *wireguard* : link-local des Gateways ermitteln] ******************************************************************************************
ok: [raspberry-wireguard] => (item={'key': 'gw04', 'value': 'fe80::27c:16ff:fec0:6c74'})
skipping: [raspberry-wireguard] => (item={'key': 'gw05', 'value': 'fe80::281:8eff:fef0:73aa'})

TASK [wireguard : *wireguard* : publickey des Gateways ermitteln] *******************************************************************************************
ok: [raspberry-wireguard] => (item={'key': 'gw04', 'value': 'TszFS3oFRdhsJP3K0VOlklGMGYZy+oFCtlaghXJqW2g='})
skipping: [raspberry-wireguard] => (item={'key': 'gw05', 'value': 'igyqOmWiz4EZxPG8ZzU537MnHhaqlwfa7HarB3KmnEg='})

TASK [wireguard : *wireguard* : Konfigurationsdatei des wireguard-Tunnels erzeugen] *************************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : systemd unit file für broker -Information anlegen] **************************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : Service broker starten beim Booten starten] *********************************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : Service wireguard via systemd starten] **************************************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : lokale link-local IPv6 Adresse aus dem PUBLIC-Key erzeugen] *****************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : checkupscript zum Testen der wireguard-Verbindung anlegen] ******************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : Ausführungsrechte des Bash-Scripts anpassen] ********************************************************************************
changed: [raspi_offloader]

TASK [wireguard : *wireguard* : crontab für minütlichen checkup der wireguard-Verbindung anlegen] ***********************************************************
changed: [raspi_offloader]

TASK [Installation von FASTD] *******************************************************************************************************************************
changed: [raspi_offloader]

TASK [Verzeichnis für fastd- Konfigurationsdatei anlegen] ***************************************************************************************************
changed: [raspi_offloader]

TASK [Schlüssel für fastd erstellen] ************************************************************************************************************************
changed: [raspi_offloader]

TASK [vxlan : *VXLAN* : Paketfilter anpassen - Eingehenden VXLAN Verkehr auf dem Mesh-Interface erlauben] ***************************************************
changed: [raspi_offloader]

TASK [vxlan : *VXLAN* : VXLAN-ID des gewählten Segments ermitteln] ******************************************************************************************
skipping: [raspberry-wireguard] => (item={'key': 'muc_cty', 'value': 3836090}) 
skipping: [raspberry-wireguard] => (item={'key': 'muc_nord', 'value': 1920014})
ok: [raspberry-wireguard] => (item={'key': 'muc_ost', 'value': 12097488})
skipping: [raspberry-wireguard] => (item={'key': 'muc_sued', 'value': 12815947}) 
skipping: [raspberry-wireguard] => (item={'key': 'muc_west', 'value': 29149}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_nord', 'value': 403289}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_ost', 'value': 12645856}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_sued', 'value': 12090508}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_west', 'value': 935867}) 
skipping: [raspberry-wireguard] => (item={'key': 'gauting', 'value': 4681119}) 
skipping: [raspberry-wireguard] => (item={'key': 'freising', 'value': 4669918}) 
skipping: [raspberry-wireguard] => (item={'key': 'welt', 'value': 4831583})

TASK [vxlan : *VXLAN* : link-local des Gateways ermitteln] **************************************************************************************************
ok: [raspberry-wireguard] => (item={'key': 'gw04', 'value': 'fe80::27c:16ff:fec0:6c74'})
skipping: [raspberry-wireguard] => (item={'key': 'gw05', 'value': 'fe80::281:8eff:fef0:73aa'})

TASK [vxlan : *VXLAN* : lokale link-local IPv6 Adresse aus dem PUBLIC-Key erzeugen] *************************************************************************
changed: [raspi_offloader]

TASK [vxlan : *VXLAN* : Startupdatei für VXLAN kopieren] ****************************************************************************************************
changed: [raspi_offloader]

TASK [vxlan : *VXLAN* : Ausführungsrechte des Bash-Scripts anpassen] ****************************************************************************************
changed: [raspi_offloader]

TASK [vxlan : *VXLAN* : systemd-unitfile anlegen] ***********************************************************************************************************
changed: [raspi_offloader]

TASK [vxlan : *VXLAN* : Neues Unitfile dem systemd bekannt geben] *******************************************************************************************
changed: [raspi_offloader]

TASK [vxlan : *VXLAN* : Service vxlan via systemd starten] **************************************************************************************************
changed: [raspi_offloader]

TASK [ext-respondd : Installation der Pakete git und python3-netifaces] *************************************************************************************
changed: [raspi_offloader]

TASK [ext-respondd : Repo ext-respondd klonen] **************************************************************************************************************
changed: [raspi_offloader]

TASK [ext-respondd : Systemd Startdatei für respondd kopieren] **********************************************************************************************
changed: [raspi_offloader]

TASK [ext-respondd : Erstellen der resondd Konfigurationsdatei alias.json] **********************************************************************************
changed: [raspi_offloader]

TASK [ext-respondd : Erstellen der resondd Konfigurationsdatei config.json] *********************************************************************************
changed: [raspi_offloader]

TASK [ext-respondd : Service ext-respondd beim Booten starten] **********************************************************************************************
changed: [raspi_offloader]

TASK [hostapd : Paket hostapd für WLAN installieren] ********************************************************************************************************
changed: [raspi_offloader]

TASK [hostapd : hostapd konfigurieren] **********************************************************************************************************************
changed: [raspi_offloader]

TASK [hostapd : hostapd Konfigurationsdatei anlegen] ********************************************************************************************************
changed: [raspi_offloader]

TASK [hostapd : wlan0 in Bridge packen] *********************************************************************************************************************
changed: [raspi_offloader]

TASK [hostapd : Service hostapd beim Booten und jetzt starten und das Laden der Unit Datei vom Service hostapd ermöglichen] *********************************
changed: [raspi_offloader]

TASK [client-mesh : Konfiguration des Client-VLAN ohne Mesh-Netz] *******************************************************************************************
changed: [raspi_offloader]

TASK [client-mesh : vxlan_id für ausgewähltes Segment ermitteln] ********************************************************************************************
skipping: [raspberry-wireguard] => (item={'key': 'muc_cty', 'value': 10758607}) 
skipping: [raspberry-wireguard] => (item={'key': 'muc_nord', 'value': 15521492})
ok: [raspberry-wireguard] => (item={'key': 'muc_ost', 'value': 2948862})
skipping: [raspberry-wireguard] => (item={'key': 'muc_sued', 'value': 8599288}) 
skipping: [raspberry-wireguard] => (item={'key': 'muc_west', 'value': 7318933}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_nord', 'value': 5705961}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_ost', 'value': 4892713}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_sued', 'value': 16544703}) 
skipping: [raspberry-wireguard] => (item={'key': 'uml_west', 'value': 16677749}) 
skipping: [raspberry-wireguard] => (item={'key': 'gauting', 'value': 16175732}) 
skipping: [raspberry-wireguard] => (item={'key': 'freising', 'value': 12937858}) 
skipping: [raspberry-wireguard] => (item={'key': 'welt', 'value': 16306234})

TASK [client-mesh : Konfiguration des Mesh-VLAN ohne Client-VLAN] *******************************************************************************************
skipping: [raspi_offloader]

TASK [client-mesh : Konfiguration von Mesh- und Client-VLAN] ************************************************************************************************
changed: [raspi_offloader]

TASK [client-mesh : Konfiguration des bevorzugte Meshingpoint in BATMAN_V ohne Wifi-Nutzung] ****************************************************************
skipping: [raspi_offloader]

TASK [client-mesh : Konfiguration des bevorzugte Meshingpoint in BATMAN_V mit Wifi-Nutzung ******************************************************************
changed: [raspi_offloader]

TASK [oled : Für OLED-Konfiguration i2c-bcm2708 in /etc/modules eintragen] **********************************************************************************
changed: [raspi_offloader]

TASK [oled : Für OLED-Konfiguration i2c-dev in /etc/modules eintragen] **************************************************************************************
changed: [raspi_offloader]

TASK [oled : Installation der für das OLED benötigten Pakete] ***********************************************************************************************
changed: [raspi_offloader]

TASK [oled : Laden des Kernelmodul i2c_arm beim Booten veranlassen] *****************************************************************************************
changed: [raspi_offloader]

TASK [oled : Reboot nach Konfigurationsänderung] ************************************************************************************************************
changed: [raspi_offloader]

TASK [oled : Repo Adafruit_Python_SSD1306 klonen] ***********************************************************************************************************
changed: [raspi_offloader]

TASK [oled : Für OLED-Konfiguration Adafruit_Python_SSD1306 installieren] ***********************************************************************************
changed: [raspi_offloader]

TASK [oled : Script zur Anzeige klonen] *********************************************************************************************************************
changed: [raspi_offloader]

TASK [oled : Script zur Bandbreitenauslastung anpassen] *****************************************************************************************************
changed: [raspi_offloader]

TASK [oled : Startscript für das OLED anlegen] **************************************************************************************************************
changed: [raspi_offloader]

TASK [oled : Service oled-bandwidth beim Booten starten] ****************************************************************************************************
changed: [raspi_offloader]

TASK [final : Reboot nach Abschluss der Konfiguration unseres Offloaders] ***********************************************************************************
changed: [raspi_offloader]

PLAY RECAP *****************************************************************************************************************************
raspi_offloader          : ok=80   changed=71   unreachable=0    failed=0    skipped=3    rescued=0    ignored=1

Auch hier wird nach Beendigung des Ansible-Laufs der Knoten auf der Freifunkkarte an der gewünschten Stelle auftauchen. Nach dem letzten Reboot, der automatisch ausgeführt wird, finden wir unseren Offloader auf der Freifunkkarte:

Bild: Ausschnitt aus der Freifunk Karte

Links


1)
Secure SHell
2)
Secure SHell
3) , 8)
Version v4 vom 12.12.2020
4)
Version v3 vom 20.11.2020
5)
Version v2 vom 09.03.2020
6)
Version v1 vom 14.02.2020
7)
Stand: November 2020
Diese Website verwendet Cookies. Durch die Nutzung der Website stimmen Sie dem Speichern von Cookies auf Ihrem Computer zu. Außerdem bestätigen Sie, dass Sie unsere Datenschutzbestimmungen gelesen und verstanden haben. Wenn Sie nicht einverstanden sind, verlassen Sie die Website.Weitere Information
  • centos/ansible/ffmuc-rpb4-ol.txt
  • Zuletzt geändert: 14.12.2020 20:53.
  • von django