This blog documents my ongoing progress with LibreMesh during Google Summer of Code (GSoC) 2025. Specifically, I’m focusing on integrating OpenWrt-native solutions and simplifying LibreMesh modules.
Currently, I am working on two main tasks:
- Replacing deferrable-reboot with watchcat: Migrating LibreMesh’s custom reboot scheduling script to the built-in OpenWrt watchcat package for improved reliability.
- Migrating DHCP functionality from dnsmasq to odhcpd: Transitioning DHCP and IPv6 handling to OpenWrt’s native odhcpd, currently in development and community testing.
For testing and validation, I’m using three physical routers configured to simulate realistic network conditions.
Task 1: Integrate OpenWrt’s watchcat via Hardware Detection
a. Motivation
The primary motivation for replacing LibreMesh’s deferrable-reboot script with OpenWrt’s watchcat is to leverage upstream-maintained tools, reduce redundancy, and enhance maintainability. watchcat provides robust functionality including scheduled reboots and network monitoring to automatically reboot routers in case of failure.
The design involves creating a hardware-detection (HWD) module within LibreMesh, enabling dynamic generation of watchcat configurations from user-defined UCI entries.
b. Implementation Details
The new package, lime-hwd-watchcat
, is implemented in Lua, performing the following:
- Unique Section Identification: Creates unique configuration section names prefixed with hardware identifiers to avoid conflicts.
- Cleaning Up Configurations: Removes previously generated watchcat configurations.
- Dynamic Configuration Generation: Reads entries from LibreMesh’s UCI configuration (
hwd_watchcat
) and generates corresponding/etc/config/watchcat
entries. - Service Management: Automatically reloads watchcat after applying configuration changes using the
/etc/init.d/watchcat reload
command.
c. Testing & Validation
Testing involved:
- Configuring custom UCI settings under
config hwd_watchcat
. - Validating automatic generation and updates to
/etc/config/watchcat
. - Confirming the proper removal of old configurations.
- Checking watchcat service status and reload logs for expected behavior.
Default configuration:

Lets change it with the new package! Using:
uci add lime-node hwd_watchcat
uci set lime-node.@hwd_watchcat[-1].mode='ping_reboot'
uci set lime-node.@hwd_watchcat[-1].pinghosts='4.2.2.2'
uci set lime-node.@hwd_watchcat[-1].pingperiod='30s'
uci set lime-node.@hwd_watchcat[-1].period='6h'
uci set lime-node.@hwd_watchcat[-1].forcedelay='1m'
uci commit lime-node
And after using ‘lime-config’

d. Resources
You can see the code and the PRs for this package here:
Pull Request approved
Task 2: Replace dnsmasq DHCP with odhcpd
a. Motivation
OpenWrt’s native odhcpd daemon already powers IPv6 RA/DHCPv6 and integrates tightly with ubus. The goal is to phase out dnsmasq
’s DHCP functionality in favor of odhcpd
, leveraging its superior IPv6 support, integration with OpenWrt, and streamlined lease handling.
The new shared-state-odhcpd_leases
package watches local leases, serialises them as CRDT objects via shared-state-async, and injects remote leases back into odhcpd
, giving every node the same “view” of the network.
b. Implementation Details
The new package is entirely based in Lua. Its components fall into three small groups:
- UCI defaults script (
90_odhcpd-lease-share
) – executed once at install time.- registers a community-scoped CRDT called
odhcpd-leases
, telling shared-state to refresh every two minutes and to expire entries after twenty; - sets two critical odhcpd options:
leasetrigger
points to our publisher script, andmaindhcp='1'
turns odhcpd into the sole DHCP server; - creates a legacy-friendly symlink
/etc/ethers → /tmp/ethers.mesh
; - finally reloads odhcpd so the new trigger takes effect.
- registers a community-scoped CRDT called
- Publisher (
shared-state-publish_odhcpd_leases
) – called by odhcpd whenever a lease changes.
It fetches the current lease table withubus call dhcp ipv4leases
, distils it to the minimum JSON mapping IP → {mac,hostname}, and pushes that into the CRDT bus withshared-state-async insert odhcpd-leases
. - Generator (
shared-state-generate_odhcpd_leases
) – executed on every CRDT update that the node receives.
It writes the merged dataset to/tmp/ethers.mesh
, moves the file atomically, and reloads odhcpd so the daemon immediately serves and announces the foreign leases as if they were local.
Unit tests live in tests/test_publish_odhcpd_leases.lua
; they stub ubus, io.popen and os.execute to validate. The tests run in CI, so regressions in JSON shape or error handling are caught before merging.
c. Testing & Validation
The following testing methods are in progress:
- Unit tests verify robustness of JSON serialization and shared-state publishing logic, covering normal, empty, and malformed market cases.
- Deployment tests across three routers:
- Confirm
odhcpd
takes over DHCP (uci show dhcp
showsmaindhcp=1
). - Check presence and updates of
/tmp/ethers.mesh
and/etc/ethers
symlink. - Simulate lease assignment and verify real-time propagation between nodes.
- Confirm
- Service behavior:
- Observe
leasetrigger
invocation onodhcpd-update
. - Ensure stable operation over lease churn and node restarts.
- Observe
So, for show how this works, I’ve two routers running LibreMesh, node-1 and node-2.
I connect a device in node-1, then I confirm it with ubus call dhcp ipv4leases '{}'

Then the publisher fires and odhcpd runs the shared-state-publish_odhcpd_leases
script, which inserts the JSON blob into the CRDT bus.
Seconds later, on node-2 I dump the CRDT and see the same lease authored by node-1:

This is a minimal example, feel free to test anything you want!
d. Resources
Pull Request of the package,.
Task 2 remains actively in development. Upcoming efforts will involve extensive community testing and careful analysis of how removing dnsmasq
‘s DHCP functionality impacts related features and dependencies.
Reflection
The first half of the project required me to dive deeper into LibreMesh’s internals than initially expected, giving me a profound appreciation for this powerful mesh networking tool.
The most valuable lesson was recognizing that removing code (such as the deferrable-reboot
script or dnsmasq
’s DHCP logic) can be just as rewarding as adding new features. Simplifying the stack enhances its predictability and maintainability, ultimately benefiting the entire LibreMesh community.
Conclussion
After these two initial tasks, LibreMesh now:
- Reboots through watchcat, an OpenWrt-native tool with LuCI support,
- Serves and synchronizes DHCP leases via odhcpd and a lightweight CRDT-based sharing mechanism,
- Incorporates automated tests to ensure reliability and stability through continuous integration (CI).
Looking ahead, I will begin Task 3, removing VLANs from Babel interface, and start prototyping the layer-2-only variant of LibreMesh. I’ll continue employing the methodology proven successful so far: iterative development, backward compatibility, and comprehensive instrumentation.
If future milestones proceed as smoothly, the project will conclude with a cleaner codebase, easier network management, and clearer upgrade paths for community networks.