Feat/0-cost hops for favorite routers (#7992)

* feat: implement router hop preservation for router-to-router communication

- Preserve hop_limit when both local device and previous relay are routers/CLIENT_BASE
- Only preserve hops for favorite routers to prevent abuse
- Apply to both FloodingRouter and NextHopRouter
- Update hop counting logic in MeshService for router-to-router communication

This allows routers to communicate over longer distances without
consuming hop limits, improving mesh network efficiency for
infrastructure nodes.

* chore: update protobufs submodule to latest

* Optimized to check friend list first before nodedb.

* Reverting unintended changes

* revert: remove protobufs submodule update

This reverts the protobufs submodule back to a84657c22 to remove
unintended changes from this branch.

* Slight rewrite to remove flawed NO_RELAY_NODE logic and added logic to add isFirstHop. If isFirstHop, always decrease hop_limit to avoid retry logic.

* DRY code. Remove NodeInfo logic that was left over.

* Trunk formatting
This commit is contained in:
Clive Blackledge
2025-09-25 03:17:51 -07:00
committed by GitHub
parent 18058ef507
commit fd5ca8b73c
4 changed files with 81 additions and 3 deletions

View File

@@ -69,6 +69,58 @@ Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRA
cryptLock = new concurrency::Lock();
}
bool Router::shouldDecrementHopLimit(const meshtastic_MeshPacket *p)
{
// First hop MUST always decrement to prevent retry issues
bool isFirstHop = (p->hop_start != 0 && p->hop_start == p->hop_limit);
if (isFirstHop) {
return true; // Always decrement on first hop
}
// Check if both local device and previous relay are routers (including CLIENT_BASE)
bool localIsRouter =
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_ROUTER, meshtastic_Config_DeviceConfig_Role_ROUTER_LATE,
meshtastic_Config_DeviceConfig_Role_CLIENT_BASE);
// If local device isn't a router, always decrement
if (!localIsRouter) {
return true;
}
// For subsequent hops, check if previous relay is a favorite router
// Optimized search for favorite routers with matching last byte
// Check ordering optimized for IoT devices (cheapest checks first)
for (int i = 0; i < nodeDB->getNumMeshNodes(); i++) {
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
if (!node)
continue;
// Check 1: is_favorite (cheapest - single bool)
if (!node->is_favorite)
continue;
// Check 2: has_user (cheap - single bool)
if (!node->has_user)
continue;
// Check 3: role check (moderate cost - multiple comparisons)
if (!IS_ONE_OF(node->user.role, meshtastic_Config_DeviceConfig_Role_ROUTER,
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE, meshtastic_Config_DeviceConfig_Role_CLIENT_BASE)) {
continue;
}
// Check 4: last byte extraction and comparison (most expensive)
if (nodeDB->getLastByteOfNodeNum(node->num) == p->relay_node) {
// Found a favorite router match
LOG_DEBUG("Identified favorite relay router 0x%x from last byte 0x%x", node->num, p->relay_node);
return false; // Don't decrement hop_limit
}
}
// No favorite router match found, decrement hop_limit
return true;
}
/**
* do idle processing
* Mostly looking in our incoming rxPacket queue and calling handleReceived.