Skip to content

APuP/batman-adv: address #1200 review (fail-fast primitives, limed guard, cleanup)#16

Open
Fede654 wants to merge 4 commits into
javierbrk:fix/ap-up_batman_macfrom
Fede654:apup-batman-review-fixes
Open

APuP/batman-adv: address #1200 review (fail-fast primitives, limed guard, cleanup)#16
Fede654 wants to merge 4 commits into
javierbrk:fix/ap-up_batman_macfrom
Fede654:apup-batman-review-fixes

Conversation

@Fede654

@Fede654 Fede654 commented Jun 19, 2026

Copy link
Copy Markdown

Follow-up on libremesh#1200 picking up the pending review changes (per @javierbrk's "if anyone wants to pick it up in the meantime, that's ok with me"). This PR targets the fix/ap-up_batman_mac branch so it folds back into libremesh#1200.

Each commit maps to a specific review request and keeps the design criteria already agreed in the thread (fail-fast primitives, defensive handling only at the call site, reuse of existing idioms, no leaked globals / dead code). All unit tests pass (./run_tests): 305 successes / 0 failures / 0 errors, unchanged count vs. the current head.

Changes

1. utils.split fails on an empty separator (commit 1)
Replaces the silent whitespace default with assert(sep ~= nil and sep ~= '', ...), and drops the nil/empty-string guard that was only there to absorb get_mac returning nil (now fixed at its source). Audited all 18 call sites: every one passes an explicit non-empty separator, and gmatch already yields {} for an empty input string, so valid callers are unaffected.

Addresses: "empty separator should be treated as error, the function should fail in that case because calling it without separator is symptomatic of something wrong in the caller."

2. network.get_mac fails fast; device_exists via stat (commit 2)
get_mac now asserts when the interface has no MAC (does not exist) instead of returning nil, surfacing the caller bug with a clear message. The NAK'd test is updated to assert.has_error. Separately, network.device_exists is reimplemented with fs.lstat("/sys/class/net/"..dev) — the same lookup already used by network.assert_interface_exists and get_own_macs — instead of io.popen("ip link show") + stdout parsing, since it runs on the hot path of every peer notification.

Addresses: "better to fail ASAP if the MAC address for a non-existent device is requested, instead of propagating a nil value upstream" and the NAK on the nil-returning test.

3. limed: skip a missing APuP peer before configuring it (commit 3)
Moves the device_exists guard ahead of network.createStatic, since createStatic is what shells out to ip link set up / ip address add and produced the No such device errors. The verbose pasted-log comment is replaced by a concise explanation: this is an expected transient during a wifi down/wifi up cycle (the APuP peer interfaces are not torn down in sync and reappear on re-association), not an error. Also fixes the skip log line, which passed the ifname as a second arg to a string.format call with no specifier, silently dropping it.

Addresses the question on whether the missing-interface condition is normal or an error: it is a normal transient, now handled and documented as such.

4. lime-proto-batadv: scope the per-peer MAC to a local + cleanup (commit 4)
macaddr was assigned without local, leaking a global; scoped to the function. The derivation is unchanged and now documented inline: 02 : id[2] : id[3] : radio[4] : radio[5] : radio[6] (locally-administered unicast; two bytes from the md5-derived interface id, low three bytes from the radio MAC — unique per peer, keeps node identity). utils.log uses a format string instead of concatenation, and the commented-out batctl if add dead code is replaced with a one-line rationale.

Design note

The review asked for fail-fast in the primitives; the defensive nil-tolerance existed because of the wifi down/up race. These reconcile by keeping the primitives strict and putting the tolerance only where the transient is legitimate — the device_exists guard in limed — which is exactly what makes the downstream fail-fast safe. No robustness is lost.

Fede654 and others added 4 commits June 19, 2026 21:23
Calling utils.split without a separator is symptomatic of a bug in the
caller, so fail fast with assert() rather than silently defaulting to a
whitespace separator. Also drops the nil/empty-string guard that was only
added to paper over network.get_mac returning nil (fixed at its source in
a separate commit); every caller passes an explicit non-empty separator and
gmatch already yields {} for an empty input string, so behaviour for valid
callers is unchanged.

Addresses review: "empty separator should be treated as error, the function
should fail in that case because calling it without separator is symptomatic
of something wrong in the caller."

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
network.get_mac() now assert()s when the interface has no MAC (i.e. it does
not exist) instead of returning nil, so a caller bug surfaces immediately
with a clear message instead of propagating a nil up the call stack. The
unit test is updated accordingly to assert the error.

network.device_exists() is reimplemented to stat /sys/class/net/<dev> via
fs.lstat -- the same lookup already used by network.assert_interface_exists
and network.get_own_macs -- instead of shelling out to "ip link show" and
parsing stdout. It is on the hot path of every APuP peer notification, so a
single stat is both cheaper and consistent with the rest of the module.

Addresses review: "better to fail ASAP if the MAC address for a non-existent
device is requested, instead of propagating a nil value upstream" and the NAK
on the nil-returning test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
During a "wifi down" / "wifi up" cycle the APuP peer interfaces are not torn
down in sync with the rest of the radio, so limed can be notified about a
peer whose linux device no longer exists. This is an expected transient (the
peer reappears once it re-associates), not an error.

Move the network.device_exists() guard ahead of network.createStatic() so we
skip the peer before touching it: createStatic shells out to "ip link set up"
and "ip address add" on the device, which are exactly the calls that produced
the "No such device" errors. The verbose pasted-log comment is replaced with a
concise explanation answering the reviewer's question (normal transient, not an
error), and the skip log line now actually interpolates the ifname (it was
passed as a second arg to a utils.log/string.format call with no format
specifier, so it was silently dropped).

Addresses review question on whether the missing-interface condition is normal
or an error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The unique per-peer MAC was assigned to a global `macaddr` (missing `local`),
leaking it into the global namespace; scope it to the function. The byte
layout is unchanged (02 : id[2] : id[3] : radio[4] : radio[5] : radio[6], i.e.
a locally-administered unicast MAC, two bytes from the md5-derived interface id
and the low three bytes of the radio MAC) and is now documented inline. The
utils.log call uses a proper format string instead of concatenation (utils.log
runs string.format, so a stray '%' in a value would have thrown), and the
commented-out "batctl if add" dead code is replaced by a one-line note
explaining the interface is attached to batman-adv through the static config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant