Add rxDupe, txRelay and txRelayCanceled to LocalStats (#4936)

* Introduce `isFromUs()` and `isToUs()`

* Add rxDupe, txRelay and txRelayCanceled to LocalStats
This commit is contained in:
GUVWAF 2024-10-04 13:28:51 +02:00 committed by GitHub
parent 236374491b
commit 673fe294f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 71 additions and 44 deletions

View File

@ -22,10 +22,12 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
{
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
printPacket("Ignoring dupe incoming msg", p);
rxDupe++;
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
// cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater!
Router::cancelSending(p->from, p->id);
if (Router::cancelSending(p->from, p->id))
txRelayCanceled++;
}
return true;
}
@ -36,12 +38,12 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
{
bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0);
if (isAckorReply && p->to != getNodeNum() && p->to != NODENUM_BROADCAST) {
if (isAckorReply && !isToUs(p) && p->to != NODENUM_BROADCAST) {
// do not flood direct message that is ACKed or replied to
LOG_DEBUG("Rxd an ACK/reply not for me, cancel rebroadcast.\n");
Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM
}
if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {
if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) {
if (p->id != 0) {
if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) {
meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it

View File

@ -86,7 +86,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
auto ourNodeNum = nodeDB->getNodeNum();
bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum;
bool toUs = mp.to == NODENUM_BROADCAST || isToUs(&mp);
for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i;
@ -141,8 +141,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
// because currently when the phone sends things, it sends things using the local node ID as the from address. A
// better solution (FIXME) would be to let phones have their own distinct addresses and we 'route' to them like
// any other node.
if (isDecoded && mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) &&
!currentReply) {
if (isDecoded && mp.decoded.want_response && toUs && (!isFromUs(&mp) || isToUs(&mp)) && !currentReply) {
pi.sendResponse(mp);
ignoreRequest = ignoreRequest || pi.ignoreRequest; // If at least one module asks it, we may ignore a request
LOG_INFO("Asked module '%s' to send a response\n", pi.name);

View File

@ -19,7 +19,7 @@ bool CompareMeshPacketFunc(const meshtastic_MeshPacket *p1, const meshtastic_Mes
auto p1p = getPriority(p1), p2p = getPriority(p2);
// If priorities differ, use that
// for equal priorities, prefer packets already on mesh.
return (p1p != p2p) ? (p1p > p2p) : (getFrom(p1) != nodeDB->getNodeNum() && getFrom(p2) == nodeDB->getNodeNum());
return (p1p != p2p) ? (p1p > p2p) : (!isFromUs(p1) && isFromUs(p2));
}
MeshPacketQueue::MeshPacketQueue(size_t _maxLen) : maxLen(_maxLen) {}

View File

@ -50,5 +50,11 @@ extern Allocator<meshtastic_MeshPacket> &packetPool;
*/
NodeNum getFrom(const meshtastic_MeshPacket *p);
// Returns true if the packet originated from the local node
bool isFromUs(const meshtastic_MeshPacket *p);
// Returns true if the packet is destined to us
bool isToUs(const meshtastic_MeshPacket *p);
/* Some clients might not properly set priority, therefore we fix it here. */
void fixPriority(meshtastic_MeshPacket *p);

View File

@ -196,6 +196,18 @@ NodeNum getFrom(const meshtastic_MeshPacket *p)
return (p->from == 0) ? nodeDB->getNodeNum() : p->from;
}
// Returns true if the packet originated from the local node
bool isFromUs(const meshtastic_MeshPacket *p)
{
return p->from == 0 || p->from == nodeDB->getNodeNum();
}
// Returns true if the packet is destined to us
bool isToUs(const meshtastic_MeshPacket *p)
{
return p->to == nodeDB->getNodeNum();
}
bool NodeDB::resetRadioConfig(bool factory_reset)
{
bool didFactoryReset = false;

View File

@ -186,7 +186,7 @@ ErrorCode RadioLibInterface::send(meshtastic_MeshPacket *p)
#ifndef LORA_DISABLE_SENDING
printPacket("enqueuing for send", p);
LOG_DEBUG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
LOG_DEBUG("txGood=%d,txRelay=%d,rxGood=%d,rxBad=%d\n", txGood, txRelay, rxGood, rxBad);
ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN;
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
@ -353,6 +353,8 @@ void RadioLibInterface::completeSending()
if (p) {
txGood++;
if (!isFromUs(p))
txRelay++;
printPacket("Completed sending", p);
// We are done sending that packet, release it

View File

@ -107,7 +107,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
/**
* Debugging counts
*/
uint32_t rxBad = 0, rxGood = 0, txGood = 0;
uint32_t rxBad = 0, rxGood = 0, txGood = 0, txRelay = 0;
public:
RadioLibInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,

View File

@ -78,7 +78,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
* Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and
* flooding this ACK back to the original sender already adds redundancy. */
bool isRepeated = p->hop_start == 0 ? (p->hop_limit == HOP_RELIABLE) : (p->hop_start == p->hop_limit);
if (wasSeenRecently(p, false) && isRepeated && !MeshModule::currentReply && p->to != nodeDB->getNodeNum()) {
if (wasSeenRecently(p, false) && isRepeated && !MeshModule::currentReply && !isToUs(p)) {
LOG_DEBUG("Resending implicit ack for a repeated floodmsg\n");
meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p);
tosend->hop_limit--; // bump down the hop count
@ -102,9 +102,7 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
*/
void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
{
NodeNum ourNode = getNodeNum();
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability)
if (isToUs(p)) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability)
if (p->want_ack) {
if (MeshModule::currentReply) {
LOG_DEBUG("Another module replied to this message, no need for 2nd ack\n");

View File

@ -169,7 +169,7 @@ ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
LOG_ERROR("Packet received with to: of 0!\n");
}
// No need to deliver externally if the destination is the local node
if (p->to == nodeDB->getNodeNum()) {
if (isToUs(p)) {
printPacket("Enqueued local", p);
enqueueReceivedMessage(p);
return ERRNO_OK;
@ -204,7 +204,7 @@ ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
*/
ErrorCode Router::send(meshtastic_MeshPacket *p)
{
if (p->to == nodeDB->getNodeNum()) {
if (isToUs(p)) {
LOG_ERROR("BUG! send() called with packet destined for local node!\n");
packetPool.release(p);
return meshtastic_Routing_Error_BAD_REQUEST;
@ -226,7 +226,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
service->sendClientNotification(cn);
#endif
meshtastic_Routing_Error err = meshtastic_Routing_Error_DUTY_CYCLE_LIMIT;
if (getFrom(p) == nodeDB->getNodeNum()) { // only send NAK to API, not to the mesh
if (isFromUs(p)) { // only send NAK to API, not to the mesh
abortSendAndNak(err, p);
} else {
packetPool.release(p);
@ -248,7 +248,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
p->from = getFrom(p);
// If we are the original transmitter, set the hop limit with which we start
if (p->from == getNodeNum())
if (isFromUs(p))
p->hop_start = p->hop_limit;
// If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it)
@ -273,7 +273,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
}
#if !MESHTASTIC_EXCLUDE_MQTT
// Only publish to MQTT if we're the original transmitter of the packet
if (moduleConfig.mqtt.enabled && p->from == nodeDB->getNodeNum() && mqtt) {
if (moduleConfig.mqtt.enabled && isFromUs(p) && mqtt) {
mqtt->onSend(*p, *p_decoded, chIndex);
}
#endif
@ -328,9 +328,9 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
memcpy(ScratchEncrypted, p->encrypted.bytes, rawSize);
#if !(MESHTASTIC_EXCLUDE_PKI)
// Attempt PKI decryption first
if (p->channel == 0 && p->to == nodeDB->getNodeNum() && p->to > 0 && p->to != NODENUM_BROADCAST &&
nodeDB->getMeshNode(p->from) != nullptr && nodeDB->getMeshNode(p->from)->user.public_key.size > 0 &&
nodeDB->getMeshNode(p->to)->user.public_key.size > 0 && rawSize > MESHTASTIC_PKC_OVERHEAD) {
if (p->channel == 0 && isToUs(p) && p->to > 0 && p->to != NODENUM_BROADCAST && nodeDB->getMeshNode(p->from) != nullptr &&
nodeDB->getMeshNode(p->from)->user.public_key.size > 0 && nodeDB->getMeshNode(p->to)->user.public_key.size > 0 &&
rawSize > MESHTASTIC_PKC_OVERHEAD) {
LOG_DEBUG("Attempting PKI decryption\n");
if (crypto->decryptCurve25519(p->from, p->id, rawSize, ScratchEncrypted, bytes)) {
@ -432,7 +432,7 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
// If the packet is not yet encrypted, do so now
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
if (p->from == nodeDB->getNodeNum()) {
if (isFromUs(p)) {
p->decoded.has_bitfield = true;
p->decoded.bitfield |= (config.lora.config_ok_to_mqtt << BITFIELD_OK_TO_MQTT_SHIFT);
p->decoded.bitfield |= (p->decoded.want_response << BITFIELD_WANT_RESPONSE_SHIFT);
@ -613,7 +613,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
#if !MESHTASTIC_EXCLUDE_MQTT
// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
if (decoded && moduleConfig.mqtt.enabled && getFrom(p) != nodeDB->getNodeNum() && mqtt)
if (decoded && moduleConfig.mqtt.enabled && !isFromUs(p) && mqtt)
mqtt->onSend(*p_encrypted, *p, p->channel);
#endif
}

View File

@ -82,6 +82,10 @@ class Router : protected concurrency::OSThread
*/
virtual ErrorCode send(meshtastic_MeshPacket *p);
/* Statistics for the amount of duplicate received packets and the amount of times we cancel a relay because someone did it
before us */
uint32_t rxDupe = 0, txRelayCanceled = 0;
protected:
friend class RoutingModule;

View File

@ -66,7 +66,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
// if handled == false, then let others look at this message also if they want
bool handled = false;
assert(r);
bool fromOthers = mp.from != 0 && mp.from != nodeDB->getNodeNum();
bool fromOthers = !isFromUs(&mp);
if (mp.which_payload_variant != meshtastic_MeshPacket_decoded_tag) {
return handled;
}

View File

@ -428,7 +428,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
drv.setWaveform(2, 0);
drv.go();
#endif
if (getFrom(&mp) != nodeDB->getNodeNum()) {
if (!isFromUs(&mp)) {
// Check if the message contains a bell character. Don't do this loop for every pin, just once.
auto &p = mp.decoded;
bool containsBell = false;

View File

@ -26,7 +26,7 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
}
// if user has changed while packet was not for us, inform phone
if (hasChanged && !wasBroadcast && mp.to != nodeDB->getNodeNum())
if (hasChanged && !wasBroadcast && !isToUs(&mp))
service->sendToPhone(packetPool.allocCopy(mp));
// LOG_DEBUG("did handleReceived\n");

View File

@ -54,7 +54,7 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
// FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER)
// to set fixed location, EUD-GPS location or just the time (see also issue #900)
bool isLocal = false;
if (nodeDB->getNodeNum() == getFrom(&mp)) {
if (isFromUs(&mp)) {
isLocal = true;
if (config.position.fixed_position) {
LOG_DEBUG("Ignore incoming position update from myself except for time, because position.fixed_position is true\n");
@ -110,7 +110,7 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
void PositionModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_Position *p)
{
// Phone position packets need to be truncated to the channel precision
if (nodeDB->getNodeNum() == getFrom(&mp) && (precision < 32 && precision > 0)) {
if (isFromUs(&mp) && (precision < 32 && precision > 0)) {
LOG_DEBUG("Truncating phone position to channel precision %i\n", precision);
p->latitude_i = p->latitude_i & (UINT32_MAX << (32 - precision));
p->longitude_i = p->longitude_i & (UINT32_MAX << (32 - precision));

View File

@ -139,7 +139,7 @@ ProcessMessage RangeTestModuleRadio::handleReceived(const meshtastic_MeshPacket
LOG_INFO.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
*/
if (getFrom(&mp) != nodeDB->getNodeNum()) {
if (!isFromUs(&mp)) {
if (moduleConfig.range_test.save) {
appendFile(mp);

View File

@ -28,7 +28,7 @@ bool RoutingModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mesh
// FIXME - move this to a non promsicious PhoneAPI module?
// Note: we are careful not to send back packets that started with the phone back to the phone
if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB->getNodeNum()) && (mp.from != 0)) {
if ((mp.to == NODENUM_BROADCAST || isToUs(&mp)) && (mp.from != 0)) {
printPacket("Delivering rx packet", &mp);
service->handleFromRadio(&mp);
}

View File

@ -310,7 +310,7 @@ ProcessMessage SerialModuleRadio::handleReceived(const meshtastic_MeshPacket &mp
// LOG_DEBUG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
// nodeDB->getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
if (getFrom(&mp) == nodeDB->getNodeNum()) {
if (!isFromUs(&mp)) {
/*
* If moduleConfig.serial.echo is true, then echo the packets that are sent out

View File

@ -333,7 +333,7 @@ void StoreForwardModule::sendErrorTextMessage(NodeNum dest, bool want_response)
if (this->busy) {
str = "S&F - Busy. Try again shortly.";
} else {
str = "S&F - Not available on this channel.";
str = "S&F not permitted on the public channel.";
}
LOG_WARN("%s\n", str);
memcpy(pr->decoded.payload.bytes, str, strlen(str));
@ -382,8 +382,7 @@ ProcessMessage StoreForwardModule::handleReceived(const meshtastic_MeshPacket &m
if ((mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) && is_server) {
auto &p = mp.decoded;
if (mp.to == nodeDB->getNodeNum() && (p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') &&
(p.payload.bytes[2] == 0x00)) {
if (isToUs(&mp) && (p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 0x00)) {
LOG_DEBUG("Legacy Request to send\n");
// Send the last 60 minutes of messages.
@ -396,7 +395,7 @@ ProcessMessage StoreForwardModule::handleReceived(const meshtastic_MeshPacket &m
storeForwardModule->historyAdd(mp);
LOG_INFO("S&F stored. Message history contains %u records now.\n", this->packetHistoryTotalCount);
}
} else if (getFrom(&mp) != nodeDB->getNodeNum() && mp.decoded.portnum == meshtastic_PortNum_STORE_FORWARD_APP) {
} else if (!isFromUs(&mp) && mp.decoded.portnum == meshtastic_PortNum_STORE_FORWARD_APP) {
auto &p = mp.decoded;
meshtastic_StoreAndForward scratch;
meshtastic_StoreAndForward *decoded = NULL;

View File

@ -127,6 +127,11 @@ void DeviceTelemetryModule::sendLocalStatsToPhone()
telemetry.variant.local_stats.num_packets_tx = RadioLibInterface::instance->txGood;
telemetry.variant.local_stats.num_packets_rx = RadioLibInterface::instance->rxGood + RadioLibInterface::instance->rxBad;
telemetry.variant.local_stats.num_packets_rx_bad = RadioLibInterface::instance->rxBad;
telemetry.variant.local_stats.num_tx_relay = RadioLibInterface::instance->txRelay;
}
if (router) {
telemetry.variant.local_stats.num_rx_dupe = router->rxDupe;
telemetry.variant.local_stats.num_tx_relay_canceled = router->txRelayCanceled;
}
LOG_INFO(

View File

@ -16,8 +16,8 @@ void TraceRouteModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtasti
// Insert unknown hops if necessary
insertUnknownHops(p, r, !incoming.request_id);
// Append ID and SNR. For the last hop (p.to == nodeDB->getNodeNum()), we only need to append the SNR
appendMyIDandSNR(r, p.rx_snr, !incoming.request_id, p.to == nodeDB->getNodeNum());
// Append ID and SNR. If the last hop is to us, we only need to append the SNR
appendMyIDandSNR(r, p.rx_snr, !incoming.request_id, isToUs(&p));
if (!incoming.request_id)
printRoute(r, p.from, p.to, true);
else

View File

@ -273,7 +273,7 @@ ProcessMessage AudioModule::handleReceived(const meshtastic_MeshPacket &mp)
{
if ((moduleConfig.audio.codec2_enabled) && (myRegion->audioPermitted)) {
auto &p = mp.decoded;
if (getFrom(&mp) != nodeDB->getNodeNum()) {
if (!isFromUs(&mp)) {
memcpy(rx_encode_frame, p.payload.bytes, p.payload.size);
radio_state = RadioState::rx;
rx_encode_frame_index = p.payload.size;

View File

@ -150,7 +150,7 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
// Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message.
// We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node
// receives it when we get our own packet back. Then we'll stop our retransmissions.
if (e.packet && getFrom(e.packet) == nodeDB->getNodeNum())
if (e.packet && isFromUs(e.packet))
routingModule->sendAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index);
else
LOG_INFO("Ignoring downlink message we originally sent.\n");
@ -162,7 +162,7 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
meshtastic_MeshPacket *p = packetPool.allocCopy(*e.packet);
p->via_mqtt = true; // Mark that the packet was received via MQTT
if (p->from == 0 || p->from == nodeDB->getNodeNum()) {
if (isFromUs(p)) {
LOG_INFO("Ignoring downlink message we originally sent.\n");
packetPool.release(p);
return;
@ -188,7 +188,7 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
const meshtastic_NodeInfoLite *rx = nodeDB->getMeshNode(p->to);
// Only accept PKI messages to us, or if we have both the sender and receiver in our nodeDB, as then it's
// likely they discovered each other via a channel we have downlink enabled for
if (p->to == nodeDB->getNodeNum() || (tx && tx->has_user && rx && rx->has_user))
if (isToUs(p) || (tx && tx->has_user && rx && rx->has_user))
router->enqueueReceivedMessage(p);
} else if (router && perhapsDecode(p)) // ignore messages if we don't have the channel key
router->enqueueReceivedMessage(p);
@ -542,7 +542,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket &
}
// check for the lowest bit of the data bitfield set false, and the use of one of the default keys.
if (mp_decoded.from != nodeDB->getNodeNum() && mp_decoded.decoded.has_bitfield &&
if (!isFromUs(&mp_decoded) && mp_decoded.decoded.has_bitfield &&
!(mp_decoded.decoded.bitfield & BITFIELD_OK_TO_MQTT_MASK) &&
(ch.settings.psk.size < 2 || (ch.settings.psk.size == 16 && memcmp(ch.settings.psk.bytes, defaultpsk, 16)) ||
(ch.settings.psk.size == 32 && memcmp(ch.settings.psk.bytes, eventpsk, 32)))) {