From: CicadaTAK Date: Sat, 3 Oct 2026 00:00:00 +0000 Subject: [PATCH] batman-adv: v: a router silent on ELP yields to a live alternative CicadaTAK-Marker: CICADATAK-BATADV-C1 BATMAN_V writes a route's throughput and last seqno only when an OGM arrives through that neighbour, so a link that dies abruptly keeps its last good score, and a worse alternative wins only once its OGM seqno leads by BATADV_OGM_MAX_ORIGDIFF (5): five OGM intervals of blackhole. CicadaTAK's 0.23.0 mesh gate measured 45-51 s at orig_interval 10 s when a pair's 2.4 GHz leg died with HaLow up throughout. ELP already tells batman, per link, that the neighbour went silent; nothing reads it for routing. In batadv_v_ogm_route_update, a router whose hardif_neigh has sent no ELP for elp_silence_factor x its announced ELP interval no longer blocks an OGM through another neighbour (the same switch the seqno rule makes later). It never deletes a route: with no live alternative, nothing changes, so a node that has walked away from every neighbour, or has one neighbour on one link, behaves as stock. elp_silence_factor is a 0644 module parameter (default 10: 5 s on a 500 ms ELP link, 20 s at 2000 ms); 0 restores stock behaviour at runtime. Plan: cicadatak.git docs/plans/failover-24-to-halow.md (C, ยง8). --- --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -42,8 +44,32 @@ #include "send.h" #include "translation-table.h" #include "tvlv.h" +#include "cicadatak_batv_yield.h" +/* CicadaTAK: see cicadatak_batv_yield.h. Runtime-tunable; 0 = stock behaviour. */ +static unsigned int elp_silence_factor = 10; +module_param(elp_silence_factor, uint, 0644); +MODULE_PARM_DESC(elp_silence_factor, + "CicadaTAK: a router silent on ELP for this many of its ELP intervals yields to a live alternative (0 = off, stock)"); +MODULE_INFO(cicadatak, "CICADATAK-BATADV-C1"); + /** + * batadv_v_router_silent() - has the router stopped sending ELP on its leg? + * @router: the current router (its hardif_neigh is always set: neigh_node_create refuses without one) + * + * Return: true when it has been ELP-silent for elp_silence_factor of its own announced ELP intervals. + */ +static bool batadv_v_router_silent(struct batadv_neigh_node *router) +{ + struct batadv_hardif_neigh_node *hn = router->hardif_neigh; + unsigned int factor = min_t(unsigned int, READ_ONCE(elp_silence_factor), 255); + + return cicadatak_batv_silent(READ_ONCE(hn->last_seen), jiffies, + msecs_to_jiffies(READ_ONCE(hn->bat_v.elp_interval)), + factor); +} + +/** * batadv_v_ogm_orig_get() - retrieve and possibly create an originator node * @bat_priv: the bat priv with all the soft interface information * @addr: the address of the originator @@ -776,7 +802,8 @@ neigh_throughput = neigh_ifinfo->bat_v.throughput; if (neigh_seq_diff < BATADV_OGM_MAX_ORIGDIFF && - router_throughput >= neigh_throughput) + router_throughput >= neigh_throughput && + !batadv_v_router_silent(router)) goto out; } --- a/net/batman-adv/cicadatak_batv_yield.h +++ b/net/batman-adv/cicadatak_batv_yield.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * CicadaTAK (CICADATAK-BATADV-C1): a router that has gone silent on ELP yields. + * + * BATMAN_V stores a route's throughput and seqno only when an OGM arrives + * through that neighbour (bat_v_ogm.c batadv_v_ogm_orig_update), so a link that + * dies abruptly keeps its last good score, and a worse alternative wins only + * once its OGM seqno leads by BATADV_OGM_MAX_ORIGDIFF: 5 OGM intervals of + * blackhole (45-51 s measured at 10 s, CicadaTAK's 0.23.0 mesh gate). ELP is + * the per-link liveness signal batman already has, and nothing reads it for + * routing. This rule does: a router whose neighbour has sent no ELP on its leg + * for factor x its announced ELP interval stops blocking a live alternative. + * It never deletes a route, so with no alternative nothing changes. + * + * Pure (no kernel headers) so CicadaTAK's host test compiles this exact text. + */ +#ifndef _NET_BATMAN_ADV_CICADATAK_BATV_YIELD_H_ +#define _NET_BATMAN_ADV_CICADATAK_BATV_YIELD_H_ + +/* Nonzero when a neighbour last heard on ELP at @last_seen (jiffies) has been + * silent for longer than @factor x @interval (its announced ELP interval, in + * jiffies). @factor 0 (the knob's "off") and an unknown interval (no ELP seen + * yet) never yield. Wrap-safe, like time_after(). + */ +static inline int cicadatak_batv_silent(unsigned long last_seen, + unsigned long now, + unsigned long interval, + unsigned int factor) +{ + if (!factor || !interval) + return 0; + return (long)(now - (last_seen + factor * interval)) > 0; +} + +#endif /* _NET_BATMAN_ADV_CICADATAK_BATV_YIELD_H_ */