Throttle NodeInfo direct responses (#11104)
This commit is contained in:
co-authored by
GitHub
parent
077c6e72f4
commit
6bff231d53
@@ -1092,6 +1092,12 @@ bool TrafficManagementModule::shouldRespondToNodeInfo(const meshtastic_MeshPacke
|
||||
if (!sendResponse)
|
||||
return true;
|
||||
|
||||
// Checked here, once a reply would actually go out, so declined requests do not consume the budget.
|
||||
if (!directResponseAllowed(getFrom(p), clockMs())) {
|
||||
TM_LOG_DEBUG("NodeInfo direct response throttled for 0x%08x", getFrom(p));
|
||||
return false;
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *reply = router->allocForSending();
|
||||
if (!reply) {
|
||||
TM_LOG_WARN("NodeInfo direct response dropped: no packet buffer");
|
||||
@@ -1144,6 +1150,43 @@ bool TrafficManagementModule::shouldRespondToNodeInfo(const meshtastic_MeshPacke
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TrafficManagementModule::directResponseAllowed(NodeNum requestor, uint32_t nowMs)
|
||||
{
|
||||
// Reached from the packet path and from runOnce, so the throttle state needs the same lock as the cache.
|
||||
concurrency::LockGuard guard(&cacheLock);
|
||||
|
||||
if (lastDirectResponseMs != 0 && (nowMs - lastDirectResponseMs) < kDirectResponseGlobalMs)
|
||||
return false;
|
||||
|
||||
DirectResponseThrottleEntry *slot = nullptr;
|
||||
for (size_t i = 0; i < kDirectResponseTrackedRequestors; i++) {
|
||||
if (directResponseSeen[i].requestor == requestor) {
|
||||
if ((nowMs - directResponseSeen[i].lastReplyMs) < kDirectResponsePerRequestorMs)
|
||||
return false;
|
||||
slot = &directResponseSeen[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot == nullptr) {
|
||||
// Unseen requester: take a free slot, otherwise reuse the least recently used one.
|
||||
slot = &directResponseSeen[0];
|
||||
for (size_t i = 0; i < kDirectResponseTrackedRequestors; i++) {
|
||||
if (directResponseSeen[i].requestor == 0) {
|
||||
slot = &directResponseSeen[i];
|
||||
break;
|
||||
}
|
||||
if (directResponseSeen[i].lastReplyMs < slot->lastReplyMs)
|
||||
slot = &directResponseSeen[i];
|
||||
}
|
||||
}
|
||||
|
||||
slot->requestor = requestor;
|
||||
slot->lastReplyMs = nowMs;
|
||||
lastDirectResponseMs = nowMs;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TrafficManagementModule::isMinHopsFromRequestor(const meshtastic_MeshPacket *p) const
|
||||
{
|
||||
int8_t hopsAway = getHopsAway(*p, -1);
|
||||
|
||||
@@ -293,6 +293,19 @@ class TrafficManagementModule : public MeshModule, private concurrency::OSThread
|
||||
|
||||
bool shouldDropPosition(const meshtastic_MeshPacket *p, const meshtastic_Position *pos, uint32_t nowMs);
|
||||
bool shouldRespondToNodeInfo(const meshtastic_MeshPacket *p, bool sendResponse);
|
||||
|
||||
// Replies go to the requesting packet's unauthenticated `from`, so space them per requester to bound
|
||||
// what any one node can be made to receive, plus a global floor on airtime.
|
||||
static constexpr uint32_t kDirectResponsePerRequestorMs = 60'000UL;
|
||||
static constexpr uint32_t kDirectResponseGlobalMs = 1'000UL;
|
||||
static constexpr size_t kDirectResponseTrackedRequestors = 8;
|
||||
struct DirectResponseThrottleEntry {
|
||||
NodeNum requestor;
|
||||
uint32_t lastReplyMs;
|
||||
};
|
||||
DirectResponseThrottleEntry directResponseSeen[kDirectResponseTrackedRequestors] = {};
|
||||
uint32_t lastDirectResponseMs = 0;
|
||||
bool directResponseAllowed(NodeNum requestor, uint32_t nowMs);
|
||||
bool isMinHopsFromRequestor(const meshtastic_MeshPacket *p) const;
|
||||
bool isRateLimited(NodeNum from, uint32_t nowMs);
|
||||
bool shouldDropUnknown(const meshtastic_MeshPacket *p, uint32_t nowMs);
|
||||
|
||||
Reference in New Issue
Block a user