From 97751df3ea383641119c6c9fa14ab3a8bf9d0747 Mon Sep 17 00:00:00 2001 From: Steve Gilberd Date: Sat, 28 Dec 2024 16:13:41 +1300 Subject: [PATCH 1/2] If a packet is heard multiple times, rebroadcast using the highest hop limit Sometimes a packet will be in the TX queue waiting to be transmitted, when it is overheard being rebroadcast by another node, with a higher hop limit remaining. When this occurs, modify the pending packet in the TX queue to avoid unnecessarily wasting hops. --- src/mesh/FloodingRouter.cpp | 4 ++++ src/mesh/MeshPacketQueue.cpp | 13 +++++++++++++ src/mesh/MeshPacketQueue.h | 3 +++ src/mesh/RadioInterface.h | 3 +++ src/mesh/RadioLibInterface.cpp | 12 ++++++++++++ src/mesh/RadioLibInterface.h | 5 +++++ 6 files changed, 40 insertions(+) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index f945409051..64280f3feb 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -29,6 +29,10 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! if (Router::cancelSending(p->from, p->id)) txRelayCanceled++; + } else if (iface && p->hop_limit > 0) { + // If we overhear a duplicate copy of the packet with more hops left than the one we are waiting to + // rebroadcast, then update the hop limit of the packet currently sitting in the TX queue. + iface->clampHopsToMax(getFrom(p), p->id, p->hop_limit - 1); } if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE && iface) { iface->clampToLateRebroadcastWindow(getFrom(p), p->id); diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index d7ee65800c..282d27b40e 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -99,6 +99,19 @@ meshtastic_MeshPacket *MeshPacketQueue::getFront() return p; } +/** Attempt to find a packet in this queue. Returns a pointer to the found packet, or NULL if not found. */ +meshtastic_MeshPacket *MeshPacketQueue::find(NodeNum from, PacketId id) +{ + for (auto it = queue.begin(); it != queue.end(); it++) { + auto p = (*it); + if (getFrom(p) == from && p->id == id) { + return p; + } + } + + return NULL; +} + /** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */ meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id, bool tx_normal, bool tx_late) { diff --git a/src/mesh/MeshPacketQueue.h b/src/mesh/MeshPacketQueue.h index b41a214b99..578280ef7b 100644 --- a/src/mesh/MeshPacketQueue.h +++ b/src/mesh/MeshPacketQueue.h @@ -35,6 +35,9 @@ class MeshPacketQueue meshtastic_MeshPacket *getFront(); + /** Attempt to find a packet in this queue. Returns a pointer to the found packet, or NULL if not found. */ + meshtastic_MeshPacket *find(NodeNum from, PacketId id); + /** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ meshtastic_MeshPacket *remove(NodeNum from, PacketId id, bool tx_normal = true, bool tx_late = true); }; \ No newline at end of file diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 652b2269cd..90f958c00d 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -185,6 +185,9 @@ class RadioInterface /** If the packet is not already in the late rebroadcast window, move it there */ virtual void clampToLateRebroadcastWindow(NodeNum from, PacketId id) { return; } + /** Clamp the hop limit to the greater of the hop count provided, or the hop count in the queue */ + virtual void clampHopsToMax(NodeNum from, PacketId id, uint32_t hop_limit) { return; } + /** * Calculate airtime per * https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 997b1d6fe0..7b972cad4c 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -344,6 +344,18 @@ void RadioLibInterface::clampToLateRebroadcastWindow(NodeNum from, PacketId id) } } +/** + * Clamp the hop limit to the greater of the hop count provided, or the hop count in the queue + */ +void RadioLibInterface::clampHopsToMax(NodeNum from, PacketId id, uint32_t hop_limit) +{ + meshtastic_MeshPacket *p = txQueue.find(from, id); + if (p && p->hop_limit < hop_limit) { + LOG_DEBUG("Increasing hop limit for packet from %d to %d", p->hop_limit, hop_limit); + p->hop_limit = hop_limit; + } +} + void RadioLibInterface::handleTransmitInterrupt() { // This can be null if we forced the device to enter standby mode. In that case diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index dff58c9add..affb00609a 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -204,4 +204,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified * If the packet is not already in the late rebroadcast window, move it there */ void clampToLateRebroadcastWindow(NodeNum from, PacketId id); + + /** + * Clamp the hop limit to the greater of the hop count provided, or the hop count in the queue + */ + void clampHopsToMax(NodeNum from, PacketId id, uint32_t hop_limit); }; \ No newline at end of file From 3041ac6c09062dac3b9f6296a98bf87f060b0f44 Mon Sep 17 00:00:00 2001 From: Steve Gilberd Date: Sat, 28 Dec 2024 16:55:52 +1300 Subject: [PATCH 2/2] Reprocess instead of modifying queued packet In order to ensure that the traceroute module works correctly, rather than modifying the hop limnit of the existing queued version of the packet, simply drop it ifrom the queue and reprocess the version of the packet with the superior hop limit. --- src/mesh/FloodingRouter.cpp | 7 +++++-- src/mesh/MeshPacketQueue.cpp | 5 +++-- src/mesh/MeshPacketQueue.h | 3 ++- src/mesh/RadioInterface.h | 7 +++++-- src/mesh/RadioLibInterface.cpp | 20 ++++++++++++++------ src/mesh/RadioLibInterface.h | 5 +++-- 6 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 64280f3feb..bf106a55e7 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -31,8 +31,11 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) txRelayCanceled++; } else if (iface && p->hop_limit > 0) { // If we overhear a duplicate copy of the packet with more hops left than the one we are waiting to - // rebroadcast, then update the hop limit of the packet currently sitting in the TX queue. - iface->clampHopsToMax(getFrom(p), p->id, p->hop_limit - 1); + // rebroadcast, then remove the packet currently sitting in the TX queue and use this one instead. + if (iface->removePendingTXPacket(getFrom(p), p->id, p->hop_limit - 1)) { + LOG_DEBUG("Processing packet %d again for rebroadcast with with better hop limit (%d)", p->hop_limit - 1); + return false; + } } if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE && iface) { iface->clampToLateRebroadcastWindow(getFrom(p), p->id); diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index 282d27b40e..6bf9b915fb 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -113,11 +113,12 @@ meshtastic_MeshPacket *MeshPacketQueue::find(NodeNum from, PacketId id) } /** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */ -meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id, bool tx_normal, bool tx_late) +meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id, bool tx_normal, bool tx_late, uint8_t hop_limit_lt) { for (auto it = queue.begin(); it != queue.end(); it++) { auto p = (*it); - if (getFrom(p) == from && p->id == id && ((tx_normal && !p->tx_after) || (tx_late && p->tx_after))) { + if (getFrom(p) == from && p->id == id && ((tx_normal && !p->tx_after) || (tx_late && p->tx_after)) && + (!hop_limit_lt || p->hop_limit < hop_limit_lt)) { queue.erase(it); return p; } diff --git a/src/mesh/MeshPacketQueue.h b/src/mesh/MeshPacketQueue.h index 578280ef7b..b76aee583e 100644 --- a/src/mesh/MeshPacketQueue.h +++ b/src/mesh/MeshPacketQueue.h @@ -39,5 +39,6 @@ class MeshPacketQueue meshtastic_MeshPacket *find(NodeNum from, PacketId id); /** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ - meshtastic_MeshPacket *remove(NodeNum from, PacketId id, bool tx_normal = true, bool tx_late = true); + meshtastic_MeshPacket *remove(NodeNum from, PacketId id, bool tx_normal = true, bool tx_late = true, + uint8_t hop_limit_lt = 0); }; \ No newline at end of file diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 90f958c00d..acb923a4f0 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -185,8 +185,11 @@ class RadioInterface /** If the packet is not already in the late rebroadcast window, move it there */ virtual void clampToLateRebroadcastWindow(NodeNum from, PacketId id) { return; } - /** Clamp the hop limit to the greater of the hop count provided, or the hop count in the queue */ - virtual void clampHopsToMax(NodeNum from, PacketId id, uint32_t hop_limit) { return; } + /** + * If there is a packet pending TX in the queue with a worse hop limit, remove it pending replacement with a better version + * @return Whether a pending packet was removed + */ + bool removePendingTXPacket(NodeNum from, PacketId id, uint32_t hop_limit_lt) { return false; } /** * Calculate airtime per diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 7b972cad4c..c99aa756b1 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -345,17 +345,25 @@ void RadioLibInterface::clampToLateRebroadcastWindow(NodeNum from, PacketId id) } /** - * Clamp the hop limit to the greater of the hop count provided, or the hop count in the queue + * If there is a packet pending TX in the queue with a worse hop limit, remove it pending replacement with a better version + * @return Whether a pending packet was removed */ -void RadioLibInterface::clampHopsToMax(NodeNum from, PacketId id, uint32_t hop_limit) +bool RadioLibInterface::removePendingTXPacket(NodeNum from, PacketId id, uint32_t hop_limit_lt) { - meshtastic_MeshPacket *p = txQueue.find(from, id); - if (p && p->hop_limit < hop_limit) { - LOG_DEBUG("Increasing hop limit for packet from %d to %d", p->hop_limit, hop_limit); - p->hop_limit = hop_limit; + meshtastic_MeshPacket *p = txQueue.remove(from, id, true, true, hop_limit_lt); + if (p) { + LOG_DEBUG("Dropping pending-TX packet %d with hop limit %d", p->id, p->hop_limit); + packetPool.release(p); + return true; } + return false; } +/** + * Remove a packet that is eligible for replacement from the TX queue + */ +// void RadioLibInterface::removePending + void RadioLibInterface::handleTransmitInterrupt() { // This can be null if we forced the device to enter standby mode. In that case diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index affb00609a..c819ae4eb4 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -206,7 +206,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified void clampToLateRebroadcastWindow(NodeNum from, PacketId id); /** - * Clamp the hop limit to the greater of the hop count provided, or the hop count in the queue + * If there is a packet pending TX in the queue with a worse hop limit, remove it pending replacement with a better version + * @return Whether a pending packet was removed */ - void clampHopsToMax(NodeNum from, PacketId id, uint32_t hop_limit); + bool removePendingTXPacket(NodeNum from, PacketId id, uint32_t hop_limit_lt); }; \ No newline at end of file