Neanderfunk 26091920sta Release: Pakete, Patches, Buildsystem

Neanderfunk 2023.2.6: Pakete, Patches, Buildsystem

Neue Neanderfunk-Stable-Firmware 26091920sta, noch Gluon 2023.2.6, aus Gründen (siehe unten). Was davon in eigenen Paketen liegt und was Patch geblieben ist:

In den Images

Auswahl in templates/common/image-customization.lua, Feed-Pin in templates/common/modules.

  • Auf allen Geräten: nodeplacer, ssid-changer, respondd, setup-mode, setup-wifi, preserve-wifichannel, hotfix, linkcheck, wifi-blackout, weeklyreboot, ap-timer, button-bind, node-whisperer, banner
  • Nur ramips-mt7621, mediatek-mt7622, mediatek-filogic: mt7915-backlog
  • Nur als DEPENDS: config-mode-theme, common
  • 64 MB RAM, zwei von Hand gepflegte Gerätelisten (18 Dualband, 29 Singleband): zram-swap dazu, procd-ujail raus. Gemessen am TL-WR1043ND v2: ujail kostete 3,7 MB RSS für dnsmasq, hostapd und ntpd zusammen.
  • Wie die Listen entstehen: Kandidaten aus einer Erhebung von RAM je Gerät (Gluon-Targets, OpenWrt Table of Hardware), aufgenommen wird, was sich im Feld als betroffen gezeigt hat. Die Listen sind nur für ath79 vollständig; Singleband-Geräte anderer Targets mit 64 MB fehlen noch, dort bleibt es beim Standard.
  • Nicht an den Listen hängen die Einstellungen, die zur Laufzeit an MemTotal entscheiden. Die greifen auf jedem Gerät mit 64 MB, auch auf denen, die in keiner Liste stehen; die Patches dazu stehen weiter unten.
  • Umsonst ist keine dieser Maßnahmen, meist zahlt es der Durchsatz.
  • Nicht drin: haveged (unter 23.05 liefert urngd die Entropie, 5.15 initialisiert den CRNG selbst; 1,6 MB RSS), ffmuc-ipv6-ra-filter (bleibt bei schnellem Supernode-Wechsel zu lange sticky)

Pakete im Einzelnen

Zur Zeile Upstream: gemeint ist fast überall freifunk-gluon/community-packages oder der Feed des jeweiligen Ursprungs-Maintainers, nicht Gluon-Core. Core betrifft es nur bei preserve-wifichannel, setup-wifi und setup-mode.

neanderfunk-preserve-wifichannel

  • Funktion: hält Kanal und Kanalbreite über Updates, setzt sie nach Site- oder Domainwechsel einmal neu
  • Mechanik: macht wifi24.preserve_channels aus der site.conf zum Default für Gluons uci-Option
  • Herkunft: Gluon 2023.2 wertet diesen site.conf-Key nicht aus. Bei uns war er jahrelang gesetzt und wirkungslos.
  • site.conf: wifi24.preserve_channels = 1
  • Dependency: Das Ausblenden des Outdoor-Schalters im Wizard bei preserve_channels=1 braucht weiterhin einen Gluon-Patch (patches/gluon-config-mode/outdoor-schalter.patch), das Paket allein genügt dafür nicht.
  • Upstream: betrifft Gluon-Core. Gluon kennt die uci-Option gluon.wireless.preserve_channels, aber keinen site.conf-Default dafür. Laufend: Gluon#3550 („RFC: configure wifi through gluon config“, offen seit 22.07.2025) baut die WLAN-Konfiguration um, Gluon#3601 (offener PR) ergänzt einen htmode-Override je Radio.

neanderfunk-setup-wifi

  • Funktion: WLAN setup.gluon_<MAC> im Setup-Mode, Einrichtung ohne Netzwerkkabel
  • Herkunft: vorher ein Firmware-Patch mit hardcodierten Werten
  • site.conf: setup_mode.wifi mit start (button, off, boot), security (open, wpa2), timeout (1200)
  • Start: per Taster im laufenden Betrieb (button), beim Start in den Setup-Mode (boot) oder gar nicht (off). Nach timeout Sekunden schaltet das WLAN wieder ab.
  • Bleibt Patch, auch beim Nachnutzen: S60dnsmasq aus gluon-setup-mode (erste Instanz fest an br-setup) und cgi-bin/portal aus gluon-config-mode-core (Rückleitung auf SERVER_ADDR). Zwei Pakete können dieselbe Datei nicht besitzen.
  • Upstream: berührt Gluon-Core. Ohne Erweiterbarkeit dieser beiden Dateien bleibt es außerhalb ein Gespann aus Patch und Paket. Älterer PR dazu: Gluon#1563 („[RFC] gluon-setup-mode: add wifi interfaces“, PR vom 04.11.2018, am 05.07.2020 ungemergt geschlossen). Offener Punkt dort: ein aus der primary_mac abgeleiteter PSK trage nicht auf allen Geräten. Unser Vorgabeschlüssel ist ebenfalls aus der MAC ableitbar.

neanderfunk-setup-mode und neanderfunk-config-mode-theme

  • Funktion: Setup-Mode auf einer Seite, Wizard und erweiterte Einstellungen, ein Speichern. Theme responsiv, mit Dark Mode.
  • Herkunft: Neuentwicklung.
  • DEPENDS: setup-mode auf +neanderfunk-config-mode-theme
  • Einbinden: '-gluon-config-mode-theme' ist Pflicht, beide liefern view/theme/layout.html.
  • Warum eine Seite: Wer in Gluons Setup-Mode vom Wizard in die erweiterten Einstellungen wechselt, verliert seine Eingaben. Ohne Wechsel kein Verlust. Oben der Wizard, darunter jedes Formular der erweiterten Einstellungen als eingeklappte Gruppe mit Zustandszeile, ein „Speichern & Neustarten“. Information und Firmware-Upgrade bleiben eigene Seiten.
  • Die Formulare bleiben die von Gluon und den Paketen. Ein neues Paket mit model() erscheint ohne Zutun als weitere Gruppe. „Außenbereich“ fragt Gluon an zwei Stellen ab, auf der Seite steht es einmal.
  • Speicherregeln: alles oder nichts, geschrieben wird nur bei durchweg gültigen Formularen; nur geänderte Formulare werden geschrieben (ein leeres Passwortformular hätte sonst passwd -l root ausgeführt); der Wizard zuletzt und immer, er setzt configured, ruft gluon-reconfigure und startet neu; solange die erweiterten Formulare schreiben, bleiben Commit und Reconfigure aus, sonst schriebe ein Formular mit altem uci-Cursor eine veraltete Kopie zurück.
  • Theme: ersetzt Gluons Theme über PROVIDES gluon-config-mode-theme, liefert nur view/theme/layout.html und ein Stylesheet und stylt Gluons eigenes Markup, ohne eines seiner Templates zu ändern. Kein Gluon-Patch nötig. Dasselbe Muster wie ffgraz-config-mode-theme-funkfeuer.
  • CSS ohne Breakpoints: keine einzige Breiten-Media-Query, das Layout richtet sich allein über Flex und Grid (26 Stellen). Die beiden einzigen @media-Regeln sind prefers-color-scheme: dark und prefers-reduced-motion: reduce. Der Dark Mode folgt dem Browser, es gibt keinen Umschalter.
  • Größen, Rohbytes: neanderfunk.css 19 651 B (gzip -9: 5 168 B), layout.html 5 142 B. Gluon zum Vergleich: gluon.css 7 073 B, layout.html 3 194 B. Unser Stylesheet deckt allerdings auch die Sammelseite mit ab, der Vergleich hinkt also.
  • Alles lokal: kein @import, kein url(), kein @font-face, kein externer Link. Nur System-Schriften (system-ui, -apple-system, Segoe UI, Roboto und weiter), das Logo als Inline-SVG. Im Setup-Mode hat der Client meist kein Internet, und Schriften kosten Flash.
  • Cache: das Stylesheet wird mit ?v=<Release> geladen. Gluon liefert /static/ ohne Cache-Control und mit festem Last-Modified aus, sonst behält der Browser nach einem Update das alte CSS.
  • i18n: eigene i18n/*.po (de, fr), geholt mit i18n('neanderfunk-config-mode-theme'), weil der Dispatcher das Layout unter dem Namen gluon-config-mode-theme rendert.
  • Upstream: Das Theme deklariert PROVIDES gluon-config-mode-theme, so wie das vorhandene ffgraz-config-mode-theme-funkfeuer in community-packages; Themes als eigenes Paket sind dort also vorgesehen. Zur Ein-Seiten-Form, die Gluon-Core berührt, kein Issue und kein PR gefunden. Ältere Issues und PRs: Gluon#2386 („Feature responsive“, PR, am 01.01.2023 ungemergt geschlossen), Gluon#528 (Farben änderbar, offen seit 16.10.2015), Gluon#1165 (Statusseite nutzt das config-mode-theme nicht, offen seit 2017).

Setup-Mode: Netze, Portal-Erkennung, Taster, LED, Timer

  • Zwei Netze. Am Kabel br-setup: Knoten 192.168.1.1, DHCP .2 bis .254, Router-Option leer, der Client bekommt also keine Default-Route über den Knoten. Im Setup-WLAN br-setupwifi: 198.51.100.1/24, DHCP .2 bis .254, Router und DNS sind der Knoten.
  • 198.51.100.0/24 ist TEST-NET-2 (RFC 5737), bewusst kein RFC 1918. Android öffnet sein Anmeldefenster nur, wenn der Probe-Host nicht auf eine RFC-1918-Adresse auflöst; am Galaxy S24 Ultra kam mit 192.168.2.1 nur „kein Internet“.
  • DNS am Kabel gezielt, im WLAN Catch-all. Am Kabel löst dnsmasq nur gluon.setup, setup.gluon und die Probe-Hosts auf, alles andere REFUSED, damit ein Laptop, der nebenher im Internet hängt, seinen anderen Resolver fragt und die OSM-Kacheln im Wizard bekommt. Im Setup-WLAN zeigt jeder Name auf den Knoten, dort lädt die Karte folglich nicht.
  • Die Probes sind Herstellerkonventionen, keine Standards. Eingetragen sind unter anderem captive.apple.com, connectivitycheck.gstatic.com, connectivitycheck.android.com, clients3.google.com, www.msftconnecttest.com, dns.msftncsi.com, detectportal.firefox.com, nmcheck.gnome.org, connectivity-check.ubuntu.com, network-test.debian.org, networkcheck.kde.org, ping.archlinux.org, connect.rom.miui.com, connectivitycheck.platform.hicloud.com.
  • Alle URLs: uhttpd läuft mit -E /cgi-bin/portal, also geht jeder Pfad, den es auf dem Knoten nicht gibt, an diesen Handler, /generate_204 ebenso wie /hotspot-detect.html, /connecttest.txt oder /success.txt.
  • Die Antwort ist für alle gleich: 302 Found, Location: http://<Adresse>/cgi-bin/config, Cache-Control: no-store (RFC 9110, 15.4.3). Adresse ist die, über die die Anfrage kam. Weil die erwartete Antwort ausbleibt, meldet das System „Im Netzwerk anmelden“ und öffnet den Wizard.
  • Nicht umgesetzt: die standardisierte Signalisierung nach RFC 8910 (DHCPv4-Option 114, DHCPv6-Option 103, RA-Option 37) samt Captive-Portal-API nach RFC 8908. Die API müsste HTTPS mit validem Zertifikat sein, sonst muss der Client sie ignorieren, und ein Knoten im Setup-Mode hat keines: Er ist offline, solange er nicht konfiguriert ist, und kann sich in dieser Lage auch keines besorgen. Dazu kommt, dass iOS die API beim ersten Verbinden nicht nutzt und dass DHCPv6 wie RA ausfallen, weil Gluons dnsmasq ohne beides gebaut ist und der Setup-Mode kein IPv6 vergibt. RFC 6585 (HTTP 511) ebenfalls nicht, wir antworten mit 302.
  • Geprüft ist Android, Galaxy S24 Ultra und ein Gerät mit Android 16 am 14.09.2026, dazu Laborläufe am Archer C25 v1. iOS, macOS, Windows, die Linux-Desktops und die Xiaomi- und Huawei-ROMs sind eingetragen, ihre Wirkung ist nicht nachgewiesen.
  • Taster: Gluon selbst startet bei 3 s Halten auf reset, wps oder phone in den Setup-Mode. Unser Paket nimmt den Kurzdruck unter 3 s und nur im Setup-Mode: Setup-WLAN an, oder der Timeout beginnt von vorn. Einen Werksreset per Taster gibt es im Image nicht, /etc/rc.button/reset fehlt.
  • LED: Setup-Mode 1000 ms an, 300 ms aus, also etwa 0,77 Hz. Läuft das Setup-WLAN, 200/60 ms, also etwa 3,8 Hz. Bis 14.09.2026 waren es 333/100, das war vom Setup-Mode-Takt zu schwer zu unterscheiden.
  • Timer: Vorgabe 1200 s, erlaubt 60 bis 86400. Verlängert wird er nur durch einen erneuten Kurzdruck, Client-Verkehr verlängert nicht. Danach wifi down und eine Logzeile, kein Neustart; der Zugang per Kabel bleibt.
  • Bei uns selbst: start = button, security = open. Das Setup-WLAN ist also offen, geht aber nur per Kurzdruck am Gerät an. check_site.lua erzwingt diese Kombination, offen gibt es nur zusammen mit button. Am Genexis Pulse EX400 zählt die kapazitive wps-Fläche für den Kurzdruck mit, dort kann das offene Setup-WLAN ohne Finger angehen.

neanderfunk-hotfix

  • Funktion: 16 Zustandsprüfungen, die WLAN neu initialisieren oder rebooten. Intervalle: healthcheck 7 min, IfNoWificlient 15 min, watchdog 5 min, WLAN-Firmware 3 min.
  • Checks und Reaktion: kernel_bug, ath_malloc, ksoftirqd_malloc, tunneldigger, br_client_ipv6, load, respondd, dropbear, wifi_firmware, ath10k_rxhang, eth_tx_stall, watchdog (Reboot); hostapd_pids, dfs_failcheck, no_wifi_clients (WLAN-Neustart); logremote (Neustart der logread-Instanz)
  • uci: hotfix.settings.check_uptime_min (5), .reboot_uptime_min (60), .watchdog_interval_min (5), .autoupdater_stale_min (300), .hostapd_cooldown_min (60), .ath10k_restart_min (3); je Check hotfix.<check>.disabled und .immediate; hotfix.load.per_cpu (2, Schwelle ist per_cpu mal Kerne über zwei Läufe); hotfix.eth_tx_stall.dry_run (1 = nur loggen), .strikes (3), .rx_strikes (5), .soft_reset (1, ethtool -r vor dem Reboot)
  • site.conf: hotfix.check_uptime_min, .reboot_uptime_min, .disabled_checks, .load_per_cpu, .eth_tx_stall_dry_run
  • Herkunft: eulenfunk/packages (Ruben Kelevra), enthält und ersetzt ffac-mt7915-hotfix. Neu gegenüber dem Vorgänger sind beide Uptime-Schwellen; das Original konnte zwei Minuten nach dem Boot rebooten.
  • Upstream: enthält und ersetzt ffac-mt7915-hotfix (community-packages#132, 2024). Die Ursachen liegen tiefer: eth_tx_stall gehört zu openwrt/openwrt#17505 („Cudy TR3000: MT7981 ethernet disconnects“, offen, zuletzt 07.01.2025), kernel_bug stammt aus der Zeit von Gluon#680 (geschlossen).
  • DEPENDS: +neanderfunk-common

neanderfunk-linkcheck

  • Funktion: prüft WLAN- und batman-Neighbours sowie Gateway-Erreichbarkeit. Intervalle: linkcheck 5 min, gateway 8 min.
  • Checks: batadv_neighbours, bsses, batinterfaces, batman_originators, bridges, bridge_ports, mesh_neighbours (erst WLAN-Neustart, dann Reboot); no_gateway, ipv6_anycast, public_prefix (Reboot)
  • uci: linkcheck.settings.check_uptime_min (5), .reboot_uptime_min (60), je Check linkcheck.<check>.disabled
  • site.conf: linkcheck.check_uptime_min, .reboot_uptime_min, .disabled_checks
  • Limits:
    • no_gateway rebootet nach 4 Läufen, also etwa 32 min, aber nur, wenn seit dem Boot einmal ein Gateway gesehen wurde (Marker /tmp/linkcheck.gw-seen). Bei flackerndem Gateway ergibt das eine Reboot-Schleife von etwa 65 min; reboot_uptime_min verzögert, es verhindert nicht. Ein Knoten, der nie ein Gateway hatte, bleibt in Ruhe.
    • bsses überspringt wifi6- und mt7915-Radios, dort bricht der Scan die Mesh-Links.
  • Herkunft: eulenfunk/packages (Ruben Kelevra).
  • DEPENDS: +neanderfunk-common

neanderfunk-wifi-blackout

  • Funktion: kein assoziierter Client auf irgendeinem Radio über blackoutwait Minuten, dann WLAN-Neustart; hilft das nicht, Reboot.
  • uci: wifi_blackout.settings.check_uptime_min (5), .restarts_before_reboot (1), .disabled (0)
  • site.conf, nicht per uci: wifi_blackout.blackoutwait (171 min), .resetwait (281 min), .stepsize (10 min)
  • False Positive: Ein Knoten, an dem legitim nie Clients hängen, also ein reiner Mesh- oder Backbone-Knoten, startet periodisch neu. Am D-Link COVR-X1860 ohne Clients gemessen: etwa alle 14 h.
  • Herkunft: FreifunkHochstift, über eulenfunk-ath9kblackout. Umbenannt, weil der Fehler nicht ath9k-spezifisch ist.
  • DEPENDS: +neanderfunk-common
  • CONFLICTS: eulenfunk-ath9kblackout, gluon-ath9kblackout, neanderfunk-ath9kblackout

neanderfunk-mt7915-backlog

  • Funktion: WLAN-Neustart, wenn der txq-Backlog eines mt7915-Radios über 50 Pakete wächst. Nur auf ramips-mt7621, mediatek-mt7622, mediatek-filogic.
  • uci: mt7915backlog.settings.threshold (50), .cooldown_min (30), .disabled (0), .check_uptime_min (5), .reboot_uptime_min (60)
  • Herkunft: Port von ffac-mt7915-backlog. Neu sind 30 min Cooldown zwischen Neustarts, das Original startete bis zu alle 2 min neu.
  • Einordnung: Symptombehandlung, bei uns zusammen mit ffac-mt7915-maxinactivity, das an der Ursache ansetzt.
  • Upstream: ffac-mt7915-backlog existiert nur als Branch in ffac/gluon-packages, PR #19 vom 30.09.2025 wurde ungemergt geschlossen. Die Ursache ist offen als openwrt/mt76#1009 („mt7915: wifi unresponsive - backlog fills - no tx activity“, zuletzt 22.04.2026). Gluon#3154 (MT7915e-Abstürze) ist seit 15.04.2025 geschlossen, behoben durch Gluon#3436 („mt76: fix system recovery routine for MT7915“, gemergt 09.03.2025), aber nur in main. Der Backport Gluon#3710 für v2023.2.x wurde nicht gemergt, Begründung im PR: „This issue is properly fixed in future Gluon releases“. Auf 2023.2.6 fehlt der Fix damit.

neanderfunk-ssid-changer

  • Funktion: schaltet die Client-SSID auf eine Offline-SSID, wenn kein Gateway erreichbar ist, und zurück, sobald es wieder da ist.
  • uci: ssid-changer.settings.enabled, .switch_timeframe (30 min), .first (5 min), .prefix (FF_Offline_), .prefix_owe (FF_Off_OWE_), .suffix (nodename, mac, none), .tq_limit_enabled (false), .tq_limit_max (45), .tq_limit_min (35), .gwofflinemaxcount (3), .debug_log_enabled
  • site.conf: Block ssid_changer
  • Limit: Die TQ-Limits funktionieren laut README nicht mit BATMAN_V.
  • Zähler liegen nicht in uci, sondern als respondd-Werte unter statistics.neanderfunk.ssid_changer.{gateway_losses, offline, switches}.
  • Herkunft: Fork von ffac-ssid-changer (Basis-Commit 91e5fa8).
  • DEPENDS: +neanderfunk-common
  • CONFLICTS: ffac-ssid-changer, gluon-ssid-changer
  • Upstream: beim Original offen: community-packages#180 („set offline ssid correctly for larger switch_timeframe“, offener PR vom 08.01.2026), #172 und #173 (Offloader ohne WLAN, 09/2025), #157 („Never sets offline SSID“, geschlossen).

neanderfunk-nodeplacer

  • Funktion: verschiebt einzelne Knoten serverseitig in eine andere Domain, gesteuert über ein signiertes Manifest auf dem Firmware-Server.
  • site.conf, alles optional, der Block selbst auch: installiert heißt aktiv. nodeplacer.mirrors (nur http://), .pubkeys, .good_signatures (höchstens Zahl der pubkeys), .disable (0), .config_mode (Tab im Setup-Mode). Ohne Angabe gelten Mirrors, Keys und Schwelle des Autoupdater-Zweigs, auf dem der Knoten läuft.
  • uci: nodeplacer.settings.*
  • Trust Anchor: dieselben Keys und dieselbe Schwelle wie der Autoupdater.
  • Limits: nur innerhalb derselben Community; mit Single-Domain-Firmware getestet, Multidomain noch nicht an Geräten.
  • CONFLICTS: gluon-hoodselector
  • Doku: neanderfunk-nodeplacer/docs/HOWTO.md und docs/MANIFEST-FORMAT.md
  • Upstream: Neuentwicklung. Verwandt, aber mit anderem Zweck: gluon-scheduled-domain-switch (ganze Domain, zeitgesteuert), gluon-hoodselector (nach Geokoordinaten), gluon-config-mode-domain-select (Auswahl durch den Betreiber). Einzelne Knoten serverseitig deckt keins davon ab. README und docs/DECISIONS.md liegen im Paket, die README bittet um Tests durch andere Communities: packages/neanderfunk-nodeplacer at afccfac4709d5a8627a3592f51cedc847c984f2c · Neanderfunk/packages · GitHub

neanderfunk-respondd

  • Funktion: respondd-Modul in C, liefert statistics.neanderfunk.*: Hardware, Radios (Kanal, htmode, txpower, Land), Offline-SSID-Zähler, Ethernet-Links (Carrier, Speed, possible), Speicherdruck (refault_file, forks, zram), Temperaturen.
  • Konfiguration: keine, weder uci noch site.conf.
  • Damit die Werte auf einer Karte erscheinen, braucht yanic eine Erweiterung. Unsere liegt öffentlich als Commit in unserem yanic-Fork: statistics.neanderfunk lesen und in die Zeitreihen schreiben · Neanderfunk/yanic@20c5b02 · GitHub
  • Nicht alles davon landet dort: Die Hardware-Angaben (vendor, soc, cpu_model, flash) liest yanic nicht, die stehen nur auf dem Knoten.
  • Upstream: Neuentwicklung. Die Feldnamen stehen bewusst unter statistics.neanderfunk.*, also als Community-Erweiterung und nicht als Gluon-Standardfeld.

neanderfunk-ap-timer

  • Funktion: Zeitschaltung für das Client-WLAN, mit Seite im Setup-Mode.
  • uci: ap-timer.settings.enabled, .type (day oder week), dazu je Tag beziehungsweise Woche list on 'HH:MM' und list off 'HH:MM'
  • site.conf: ap_timer.web (Seite im Setup-Mode, Vorgabe true)
  • Herkunft: Fork von ff-ap-timer und ff-web-ap-timer, zu einem Paket zusammengefasst (community-packages#80, 2023, ursprünglich von FFHO).
  • CONFLICTS: ff-ap-timer, ff-web-ap-timer

neanderfunk-button-bind

  • Funktion: legt Funktionen auf die Gerätetaster.
  • uci: button-bind.wifi.function: 0 = WLAN an/aus (OpenWrt-Verhalten), 1 = keine Funktion (Vorgabe), 2 = WLAN-Reset, 3 = Nachtmodus (LEDs aus, nur beim Drücken an, braucht Reboot)
  • Herkunft: Port von ffffm-button-bind (GitHub - freifunk-ffm/packages: Frankfurter Packages · GitHub), mit Bugfix im Upgrade-Skript.
  • CONFLICTS: ffffm-button-bind
  • Upstream: das Ursprungs-Repo ist nicht archiviert, letzter Push 10.07.2024.

neanderfunk-node-whisperer

  • Funktion: Diagnoseinformationen über WLAN-Beacons.
  • site.conf: node_whisperer.enabled, .information (Auswahl aus hostname, node_id, uptime, site_code, domain, system_load, firmware_version, batman_adv)
  • Herkunft: Fork von ffda-node-whisperer. Unsere Änderungen liegen als Patches im Paket: -ENODATA statt falscher Werte, Gateway-TQ über BATADV_CMD_GET_GATEWAYS, jeder Originator wird einmal gezählt.
  • CONFLICTS: ffda-node-whisperer
  • Upstream: community-packages#182 (offen seit 03.04.2026) meldet wörtlich node-whisperer: Error collecting Information for id=4 name=domain code=-1. Unser Patch 0001 setzt an genau dieser Meldung an: gluonutil_get_domain() liefert auf Single-Domain-Firmware NULL, der Collector gab dafür -1 zurück. Im Issue wird als Ursache eine unvollständige WLAN-Erkennung vermutet.

neanderfunk-banner

  • Funktion: ersetzt /etc/banner und /etc/profile durch Varianten mit Knotenstatus und Hilfsbefehlen.
  • Hinweis: macht DNS-Abfragen bei asn.cymru.com für die ASN-Anzeige.
  • CONFLICTS: ffmuc-custom-banner (community-packages#115, 2024).

neanderfunk-common

  • Funktion: gemeinsame Helfer für hotfix, linkcheck, weeklyreboot, ssid-changer und wifi-blackout, darunter das Reboot-Log /lib/gluon/neanderfunk/reboot.log, das die letzten Reboot-Gründe über den Neustart hält.
  • uci: neanderfunk.settings.reboot_log_max (6, 0 = aus)
  • site.conf: neanderfunk.reboot_log_max

neanderfunk-weeklyreboot

  • Funktion: Reboot donnerstags, cron 15 3 * * 4 plus 0 bis 9999 s Zufall, also zwischen 3:15 und etwa 6:02.
  • Übersprungen, solange der Autoupdater arbeitet, zweistufig: flock -n auf /var/lock/autoupdater.lock deckt Download und Prüfung ab, pgrep sysupgrade den Flash selbst, beides fail-safe.
  • Ohne gestellte Uhr hängt der Reboot an der Uptime statt am Wochentag. Die meisten Router haben keine RTC. Nach dem Boot setzt OpenWrt die Uhr auf den Zeitstempel der jüngsten Datei unter /etc, also etwa auf die letzte Konfigurationsänderung. Liegt der kurz vor Donnerstag 3:15, erreicht der Knoten die cron-Zeit nach jedem Boot nach derselben kurzen Frist, und frühere Fassungen starteten ihn so immer wieder neu. Das Skript prüft deshalb einen Marker in /tmp, den das ntp-Hotplug-Ereignis stratum setzt. Fehlt er, rebootet der Donnerstags-Lauf erst ab sieben Tagen Uptime, der Neustart fällt dann zwischen 7 und 14 Tagen.
  • Konfiguration: keine. Der Zeitplan ist fest; für andere Zeiten muss die cron-Zeile geändert und neu gebaut werden.
  • CONFLICTS: ffac-weeklyreboot, gluon-weeklyreboot
  • DEPENDS: +neanderfunk-common
  • Upstream: Pendant ist ffac-weeklyreboot (community-packages#34, 2023). Es prüfte /tmp/autoupdate.lock, eine Datei, die niemand anlegt. Korrigiert in community-packages#191, upstream gemergt am 10.09.2026, jetzt ebenfalls flock -n auf /var/lock/autoupdater.lock. flock ist auf den 2023.2.6-Images vorhanden (busybox 1.36.1, geprüft an x86 und TL-WR1043ND v2). Die zweite Stufe pgrep sysupgrade und der ntp-Schutz stehen upstream nicht.

Was noch Patch geblieben ist, und warum

40 Patches, feste Reihenfolge in templates/common/prepare.sh, gruppiert unter patches/<gruppe>/. Jede Gruppe ist in sich geschlossen, die Skripte sind idempotent; patches/README.md beschreibt, wie man einzelne Gruppen übernimmt.

Backports: upstream gelöst, in 2023.2 noch nicht drin

  • lowmem/limit-wireless-buffers - WLAN-Puffer nach RAM. Gluon 8f38662f, ab v2025.1.
  • lowmem/sysctl-64m-min-free - min_free_kbytes 2048, kleine Fragmentpuffer. Gluon a505f767 plus Fix c6ac8914, nur in main, in keinem Release.
  • status-page/statuspage-ssid - SSID und HT-Modus je Radio. Gluon 7c040c2d04ee, ab v2025.1, bei uns mit zwei bewussten Abweichungen.
  • kernel/rtl8221b-skip-mmd30 - MMD 30 beim C45-PHY-Scan auslassen, sonst legt das Lesen den RTL8221B lahm, wenn beim Boot ein Kabel steckt. OpenWrt 88dcd8c303b6, nur in main, weder 24.10 noch 23.05.
  • devices/add-dlink-m30 - in Gluon v2025.1.3 und main, nicht in v2023.2.x. OpenWrt 23.05 6e51ff88b0 plus Fix aus 24.10 d92fc99360. Ohne Recovery-Image, wie Gluon selbst seit freifunk-gluon/gluon#3816.

TLB-Kernelfreeze, Upstream-Regression im Gluon-2023.2.6-Release, gelöst

  • kernel/revert-mips-tlb-uniquify nimmt den Aufruf von r4k_tlb_uniquify() heraus. Betroffene MIPS-Boards bleiben sonst beim Kaltstart in tlb_init() stehen, überstehen aber Warmstarts und Updates.
  • Das ist der Grund für das „aus Gründen“ oben. An diesem Fehler ist bei uns im März eine Stable gescheitert: ausgerollt am 23.03.2026, zurückgerollt am 27.03.2026. Die Geräte liefen nach dem Update weiter, der Fehler zeigte sich erst beim nächsten Stromausfall, und dann war das Gerät weg. Auffallen konnte das also weder beim Ausrollen noch in der Update-Statistik.
  • Zurückgerollt per Manifest: ein vordatiertes, neu signiertes Manifest mit der alten Version auf einem eigenen Zweig. Der Autoupdater nimmt eine ältere Firmware, wenn das Manifest sie als die aktuelle ausweist.
  • Upstream hat es anders gelöst: 5.15.209 schreibt die Uniquifizierung neu (540760b77b8f, Fixes: 9f048fa48740). Für die Router kein funktionaler Unterschied.
  • openwrt-23.05 hat 5.15.211 seit 11.07.2026, Gluon v2023.2.x seit 22.09.2026 (freifunk-gluon/gluon#3841).
  • Unser Patch fällt beim nächsten Build zwingend weg, er setzt an Code an, den 5.15.209 umgeschrieben hat.
  • Analyse und Messung öffentlich: freifunk-docs/mips-tlb-cold-start-5.15.md at 15fcc7bc579df8d400b12c3650a87fbf45994ea7 · Neanderfunk/freifunk-docs · GitHub

Hängt an offenen Issues upstream

  • kernel/mt7530-phy-disable-eee - EEE am MT7530-PHY aus. Nachbau von OpenWrt PR #25058 (offen, Basis main), von uns auf 5.15 übertragen. Ungeprüft: gebaut, die Wirkung am Gerät ist nicht gezielt nachgemessen.
  • build/add-ffac-package-patches - max_inactivity im ffac-Paket, Umgehung für openwrt/mt76#1009 (offen): mt7915 reagiert nicht mehr, Backlog läuft voll.

Fehler und Lücken ohne Issue upstream

  • kernel/ag71xx-rx-ring-no-bug - unter RAM-Druck scheitert das Nachfüllen des RX-Rings, ag71xx_assert(0) löst einen Panic aus, obwohl der Treiber mit oom_timer einen Rückweg hat. OpenWrt main hat die Stelle unverändert (ag71xx_main.c, ag71xx_rx_packets).
  • bugfixes/tunneldigger-reinit-backoff - Mesh-VPN an, kein WAN: Reinit ohne Pause, je Reinit zwei modprobe. Am WDR3600 gemessen: 115 modprobe in 30 s, CPU 0 % idle.
  • lowmem/sysctl-no-watermark-boost-64mb und bugfixes/sysctl-firmware-no-sysfs-fallback (fehlende Firmware wie tg3 hielt den Boot 60 s unter RTNL auf). Beide ließen sich auch als Paket mit sysctl.d-Datei lösen.
  • gluon-config-mode/wizard-save-lock - Doppelklick auf „Speichern & Neustarten“ startet parallele gluon-reconfigure-Läufe, Ergebnis Hostname OpenWrt und Zeitzone UTC.
  • status-page/web-static-version - CSS und JS mit ?v=<Release> gegen alten Browser-Cache.
  • Airtime-Teil aus build/add-gluon-package-patches - respondd-module-airtime lässt Werte weg, bei denen busy, rx oder tx größer als active ist; die mt76-Survey-Zähler laufen je vif.

Prinzipiell kein Paket

  • lowmem/state-check-shell, lowmem/tunneldigger-watchdog-shell - gluon-state-check und tunneldigger-watchdog als Shell statt Lua, weil die Lua-Laufzeit auf 64-MB-Geräten jede Minute beziehungsweise alle fünf Minuten vom Flash kam. Als Paket nicht lösbar: Sie ersetzen Dateien, die Gluon-Paketen gehören, das gäbe einen opkg-Konflikt.
  • status-page/* - Gluons Statusseite hat in 2023.2 keinen Erweiterungspunkt. Die Daten kommen inzwischen aus neanderfunk-respondd, als Patch bleibt die Anzeige.
  • setup-mode-network/* - Rumpf von 14 Zeilen: die Bindung von dnsmasq an br-setup und die Portal-Umleitung. Den Rest hat neanderfunk-setup-wifi übernommen.
  • Geräte, die auch Gluon 2025.1 nicht hat: eap225-wall-v2, zyxel-nbg6616, fritz-repeater-3000, ea8300-dallas, cudy-m1800, rb750gr3, Cudy ap3000-v1 und tr3000-256mb-v1, FRITZ!Box 3390, zwei MikroTik ath79, zte-mf286r, MikroTik wAP ac, NanoPi R2C.
  • device-fixes/fix-xiaomi-ax6s-bootflags - der A/B-Bootloader des Redmi AX6S fällt sonst nach einigen Neustarts auf die Stock-Firmware zurück. Am Gerät verifiziert; ob OpenWrt das inzwischen anders löst, ist nicht geprüft.
  • Rein lokal: network/interface-role-migration21 (unsere Migration von 2021), build/patch-gluon-makefiles (GLUON_TARGETS per override).

Was neben den Images liegt

In jedem Domain-Verzeichnis liegt neben ./sysupgrade, ./factory und ./other ein Verzeichnis ./site, das den Build beschreibt. Damit hat, wer will, die Grundlage, den Build zu wiederholen. Ein reproducible build ist es nicht, es geht um Transparenz:

  • Gluon-Standard, in einer Zeile abgehandelt: site.conf, site.mk, modules, image-customization.lua und i18n/ sind das, was jede Gluon-Site hat.
  • build-info.txt - die Herkunft des Images: Release, Domain, Template, Branch, Start und Ende des Laufs, Buildhost und Aufruf, die vollen Commit-IDs von Firmware-Repo und Gluon mit dem Vermerk sauber oder N Änderungen, je Modul Soll-Commit und Ist-Stand, Target- und Domainliste, Kernel- und WLAN-Treiberversionen aus dem OpenWrt-Manifest und jeder angewendete Patch mit Ergebnis.
  • build.conf - die Laufparameter von build.sh, kommentiert: Versionsschema, make clean und git reset, -j, BROKEN, Autoupdater, Logoptionen, Name der Signierschlüsseldatei, Worker-Zahl und Platzprüfung. Welche Targets und Domains gebaut werden, steht nicht hier.
  • targets.conf - welche Gluon-Targets gebaut werden. Abgewählte stehen mit - davor, je mit der Knotenzahl kommentiert.
  • domains.conf - welche Domains in welcher Reihenfolge gebaut werden.
  • build.sh - das Buildsystem selbst: Gluon-Baum zurücksetzen, prepare aufrufen, Golden Tree und Worker-Overlays, Build-Schleife über Targets und Domains, Manifest signieren, Ergebnis samt diesem Verzeichnis ablegen.
  • prepare.sh - wendet die Patches aus patches/ in fester Reihenfolge an, in zwei Phasen vor und nach Gluons make update.
  • prepare.log - das vollständige Log der Vorbereitung, einmal je Lauf und für alle Domains gleich: Zurücksetzen, make update mit Gluons Patches, unsere Patches, Feeds und Downloads. Ohne das Kompilieren.
  • build.log.gz - das vollständige make-Log mit V=s dieser einen Domain über alle 20 Targets, rund 367 000 Zeilen. Zu beachten: Die erste gebaute Domain kompiliert alles, in jeder weiteren steht fast nur noch der Image-Zusammenbau.

Wie gebaut wird

Messbericht (englisch) mit Rohdaten und Auswertungsskript, einschließlich des Release-Laufs: firmware/docs/parallel-builds/README.md at de00b9dba382a347eab20bbc783fc7b1fd1627ff · Neanderfunk/firmware · GitHub

  • Golden Tree. Der Gluon-Baum wird einmal vollständig gebaut, seriell mit vollem -j: git reset, make clean, make update, unsere Patches, dann die erste Domain für alle Targets. Danach wird er nur noch gelesen. Darin liegt alles, was OpenWrt baut, Toolchain, Pakete, Kernel, build_dir und staging_dir je Target.
  • Wiederverwendet wird er über einen Fingerprint der Eingaben: Gluon-Commit, Targetliste, Geräteauswahl, BROKEN, gcc- und libc-Version des Hosts, SHA-256 aller Patches und gemeinsamen Templatedateien. Passt er, entfallen prepare und Golden Tree ganz. Die Patches werden dann nicht einmal neu angewendet, weil schon neue mtimes OpenWrt zum Neubau brächten.
  • Warum das überhaupt trägt: Ein Domainwechsel kompiliert kein einziges Paket, nur package/gluon-site hängt am Site-Verzeichnis. Die Kosten liegen je Image, nicht je Konfiguration, gemessen rund 94 min je Domain für 448 Images, also etwa 12,6 s je Image.
  • Worker auf Kernel-overlayfs, nicht fuse-overlayfs: lower ist der Golden Tree, per Bind-Mount festgehalten, upper ein privates Verzeichnis je Worker. Gemountet wird am Originalpfad des Baums, weil OpenWrt absolute Pfade in seine .prepared-Stempel schreibt.
  • Rootless: zwei User-Namespaces (unshare -Urm), Overlay mit userxattr, danach zurück auf die normale UID, weil OpenWrt nicht als root baut. Voraussetzungen: Linux ab 5.11, util-linux ab 2.38, bash ab 5.1, unter Ubuntu ab 23.10 zusätzlich kernel.apparmor_restrict_unprivileged_userns=0. build.sh probiert einen echten Overlay-Mount vorab und baut seriell weiter, wenn er scheitert.
  • Aufgeteilt wird nach Targets, nicht nach Domains. Ein Worker baut ein Target für alle Domains, danach wird sein upper gelöscht. Grund ist der Platz: Das Overlay wächst je Target (erste Domain 2,8 GB, jede weitere 0,2 GB), auf der Target-Achse rund 11 GB je Worker, auf der Domain-Achse wären es rund 62 GB.
  • Kosten des Overlays, gemessen: Mounten 0,00 s, Verwerfen rund 3 s für 3 GB und 70 000 Dateien. Der Overhead war mit allen Geräten von ramips-mt7621 nicht messbar (241/219 s direkt gegen 238/224 s im Overlay); mit nur zwei Geräten, wo die Fixkosten dominieren, 2,6 %.
  • Was die Parallelität bringt, gemessen: Nachfolgende Domains liefen mit sechs Workern 2,7 bis 2,8 mal schneller als seriell, nicht sechs mal. Jeder einzelne Schritt dauert unter Last etwa 1,7 mal so lang, mit neun Workern etwa 1,85 mal. Die Ursache ist eingegrenzt, aber nicht bewiesen, am ehesten der Takt unter Volllast.
  • Der Release-Lauf: 86 Varianten mal 20 Targets, 1720 Schritte, 8 Worker in drei Wellen, 37 066 Images mit zusammen 325,7 GB. Von Null an rund 40 h, verteilt auf zwei Anläufe, weil der erste nach 14 der 20 Golden-Schritte angehalten wurde. Der zweite Anlauf lief 36 h 29 min: prepare 82 min, die restlichen Golden-Schritte 136 min, Parallelphase 32,4 h bei im Mittel 6,8 von 8 belegten Workern, Abschluss 29 min. Einen seriellen Vergleichslauf dieses Umfangs gibt es nicht. Hochgerechnet aus gemessenen Einzelkosten wären es rund 138 h, gerechnet für 22 Targets.
  • Grenzen:
    • fuse-overlayfs ist untauglich. OpenWrt macht rm -rf root.orig-<target> und direkt danach cp -fpR; dort taucht das lower-Verzeichnis wieder auf und cp scheitert mit „File exists“. Kernel-overlayfs setzt das Whiteout richtig.
    • Kein overlayfs auf overlayfs. Im Container taugt /tmp nicht als upper, ein bind-gemounteter ext4-Pfad schon.
    • Der Golden Tree selbst ist seriell und bei wenigen Domains der größte Posten. Ihn zu parallelisieren ist schwer, weil alle Targets in denselben Baum bauen.
    • Die Parallelphase ist nie kürzer als das längste Target, bei uns ath79-generic, und die letzte Welle läuft mit wenigen Workern.
    • Belegt ist das auf einem Host mit wenigen Läufen. Nur eine Konfiguration wurde wiederholt, Abweichung etwa 1 %. x86-64 war nicht Teil der Overlay-Messungen.

Wenn Ihr etwas davon nachnutzen wollt

Die Pakete gehen einzeln, das Buildsystem eher nicht.

  • Feed in site/modules, gepinnt auf den Stand aus diesem Release: PACKAGES_NEANDERFUNK_REPO=https://github.com/Neanderfunk/packages.git, _BRANCH=v2023.2.x, _COMMIT=afccfac4709d5a8627a3592f51cedc847c984f2c. Gebaut für Gluon v2023.2.x.
  • Paketnamen in image-customization.lua. neanderfunk-setup-mode bringt ein eigenes Theme mit, ohne '-gluon-config-mode-theme' bricht der Build ab.
  • CONFLICTS stehen je Paket oben, das Original muss aus der Paketliste. Ausnahme: hotfix und mt7915-backlog deklarieren im Release-Stand kein CONFLICTS gegen ffac-mt7915-hotfix und ffac-mt7915-backlog. Wer beides hat, bekommt zwei parallel laufende Watchdogs, ohne Fehlermeldung. Die ffac-Pakete also von Hand herausnehmen.
  • Patches: patches/README.md im Tag, Abschnitt „Einzelne Patches übernehmen“. Gruppe kopieren, patches/lib-patch.sh dazu, Skript aus dem Gluon-Verzeichnis aufrufen, Phase beachten.
  • Nicht übernehmen: kernel/revert-mips-tlb-uniquify (in v2023.2.x seit 22.09.2026 überflüssig), lowmem/limit-wireless-buffers (entfällt mit 2025.1), network/interface-role-migration21 (unsere Migration von 2021) und alles unter build/ (unsere opkg-Schlüssel).
  • build.sh, targets.conf, Domains und Site-Templates sind auf uns zugeschnitten und nicht dafür gebaut, anderswo zu laufen.

Fragen gern hier im Thread.

Nice, danke für die ausführliche Beschreibung.

Eine Frage stellt sich mir aber:

Wenn doch aber …

… das für v2025.1 gelöst ist bzw. werden kann, warum dann noch mal v2023.2? Oder was verstehe ich hier miß?

Weil eine 2025.1.x keine 2023.2.6 ist.

Siehe Absatz „aus Gründen“.

Ein reparierter, also nutzbares 2023.2.6 Release stand seit Monaten offen.

Oder anders gesagt: Test-Releases vom 2025.1.x sollen hier nicht ein noch nicht per autoupdater ausgerolltes Release überholen.

Nachtrag: Buildsystem aufgeteilt, dazu Befehle flash, portrole, channel, offlinescan

Für potentielle Nachnutzende: Das Buildsystem ist jetzt aufgeteilt. Alle Links auf den Stand eines Testlaufs mit der neuen Aufteilung gepinnt:

Bei der Gelegenheit, in neanderfunk-banner, erst ab dem nächsten Build: