Meshtastic vs MeshCore

Technical Routing Architecture Analysis

Version Information

Meshtastic

This analysis is based on Meshtastic firmware v2.6.4 (as of May 2025)

MeshCore

This analysis is based on MeshCore v1.6.0 (as of May 2025)

Core Routing Approaches

Meshtastic Routing Architecture

Meshtastic utilizes a hybrid routing approach consisting of three main components:

  1. Flooding Router: The base routing layer that implements simple flood-based message propagation.
  2. Next Hop Router: Extends the flooding router with packet acknowledgment and retransmission.
  3. Reliable Router: Adds additional reliability mechanisms for messages that require acknowledgments.

Flooding Mechanism

When a node receives a packet:

  1. It checks if it has seen this packet before (using a duplicate detection table)
  2. If new, it decrements the hop limit and, if not zero, rebroadcasts the packet
  3. All nodes in a channel rebroadcast messages regardless of the destination
FloodingRouter Implementation
void FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p)
{
    // Never rebroadcast from the phone
    if (!iface) {
        LOG_DEBUG("No interface - dropping rebroadcast\n");
        return;
    }

    // Note: if the packet originates from the local node, do not rebroadcast as the Routing layer has already 
    // done that if it needs to. (previously this was causing duplicate rebroadcasts and interference)
    if (shouldFilterReceived(p) || p->from == getNodeNum()) {
        LOG_DEBUG("Dropping rebroadcast of received, from=0x%x, to=0x%x\n", p->from, p->to);
        return;
    }

    if (iface->findInTxQueue(p->from, p->id)) {
        LOG_DEBUG("This same packet is still in the TX queue - we will relayer anyway\n");
    }

    // Is this message destined for or from us? Then don't rebroadcast
    NodeNum ourNode = getNodeNum();
    if (p->to == ourNode || p->from == ourNode) {
        LOG_DEBUG("Dropping rebroadcast of our message, from=0x%x, to=0x%x\n", p->from, p->to);
        return;
    }

    // If the message is a broadcast or destined for our node, rebroadcast
    // broadcasts and messages directed to the phone always have max_hop_limit
    if (loopbackBroadcastsToPhone(config.lora.loopback_broadcasts_to_phone) ? isBroadcast(p->to) : p->to == NODENUM_BROADCAST) {
        // Treat messages that arrive without a hop_limit included as having a default of 3
        auto hopLimit = Default::getHopLimit(p);
        if (hopLimit > 0) {
            // rebroadcasting a broadcast packet
            LOG_DEBUG("Rebroadcasting broadcast message, from=0x%x, id=0x%x, hopLimit=%d\n", p->from, p->id, hopLimit);
            auto newP = packetPool.allocCopy(*p);
            newP->hop_limit = hopLimit - 1; // bump down the hop count
            iface->sendTo(newP);
        } else {
            LOG_DEBUG("Not rebroadcasting broadcast message, from=0x%x, id=0x%x, hopLimit=0\n", p->from, p->id);
        }
    }
}

Packet Retransmission Logic

Meshtastic implements retransmission for reliability:

  • Intermediate nodes perform up to 2 retransmissions
  • Original senders perform up to 3 retransmissions for reliable messages
  • Packets are stored in a pending retransmission queue until acknowledgment or timeout
NextHopRouter Constants
// The number of retransmissions intermediate nodes will do (actually 1 less than this)
constexpr static uint8_t NUM_INTERMEDIATE_RETX = 2;
// The number of retransmissions the original sender will do
constexpr static uint8_t NUM_RELIABLE_RETX = 3;

Congestion Control

Meshtastic scales intervals based on network congestion:

  • Router/repeater nodes don't have their intervals scaled
  • Tracker/sensor nodes get priority for position and telemetry
  • Regular nodes scale back transmission as the network grows
Congestion Scaling
uint32_t Default::getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes)
{
    // If we are a router, we don't scale the value. It's already significantly higher.
    if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER)
        return getConfiguredOrDefaultMs(configured, defaultValue);

    // Additionally if we're a tracker or sensor, we want priority to send position and telemetry
    if (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_SENSOR, meshtastic_Config_DeviceConfig_Role_TRACKER))
        return getConfiguredOrDefaultMs(configured, defaultValue);

    return getConfiguredOrDefaultMs(configured, defaultValue) * congestionScalingCoefficient(numOnlineNodes);
}

MeshCore Routing Architecture

MeshCore employs a more selective routing approach with distinct routing modes:

  1. Flood Routing: Similar to Meshtastic but with priority-based retransmission
  2. Direct Routing: Path-specific routing with selective forwarding
  3. Zero-Hop Routing: For local broadcast without retransmission

Selective Packet Forwarding

MeshCore only forwards packets if they match specific criteria:

  • Only forwards direct-routed packets if this node is the next hop
  • Does not retransmit packets it has seen before
  • Removes its hash from the path before rebroadcasting direct packets
Packet Routing Logic
DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
  if (pkt->isRouteDirect() && pkt->path_len >= PATH_HASH_SIZE) {
    if (self_id.isHashMatch(pkt->path) && allowPacketForward(pkt)) {
      if (_tables->hasSeen(pkt)) return ACTION_RELEASE;  // don't retransmit!

      // remove our hash from 'path', then re-broadcast
      pkt->path_len -= PATH_HASH_SIZE;
      memcpy(pkt->path, &pkt->path[PATH_HASH_SIZE], pkt->path_len);

      uint32_t d = getDirectRetransmitDelay(pkt);
      return ACTION_RETRANSMIT_DELAYED(0, d);  // Routed traffic is HIGHEST priority 
    }
    return ACTION_RELEASE;   // this node is NOT the next hop (OR this packet has already been forwarded), so discard.
  }
  // Additional routing logic...
}

Priority-Based Transmission

MeshCore uses a priority system for transmissions:

  • Direct messages get highest priority (0)
  • Regular messages get medium priority (1)
  • Path discovery packets get lower priority (2)
  • Advertisements get lowest priority (3)
Flood Routing with Priority
void Mesh::sendFlood(Packet* packet, uint32_t delay_millis) {
  packet->header &= ~PH_ROUTE_MASK;
  packet->header |= ROUTE_TYPE_FLOOD;
  packet->path_len = 0;

  _tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us

  uint8_t pri;
  if (packet->getPayloadType() == PAYLOAD_TYPE_PATH) {
    pri = 2;
  } else if (packet->getPayloadType() == PAYLOAD_TYPE_ADVERT) {
    pri = 3;   // de-prioritie these
  } else {
    pri = 1;
  }
  sendPacket(packet, pri, delay_millis);
}

Congestion Mitigation

MeshCore employs several congestion mitigation techniques:

  • Airtime Budget: Nodes limit to approximately 33% airtime utilization
  • Randomized Delays: Prevents collision storms after regional events
  • Path-Based Priority: Messages closer to source get higher priority
Airtime Budget
float Dispatcher::getAirtimeBudgetFactor() const {
  return 2.0;   // default, 33.3%  (1/3rd)
}
Randomized Delay Implementation
// Multiple nodes around sender could all try to rebroadcast at once, so apply a random delay
uint32_t rand_delay = _rng->nextInt(ANNOUNCE_DELAY_MIN, ANNOUNCE_DELAY_MAX);

Network Capacity Analysis for Large-Scale Disasters

This analysis examines how each platform would perform in a large-scale disaster scenario with approximately 50,000 people trying to communicate across a mesh of 1,000 nodes in 300 km².

Meshtastic Network Capacity

Broadcast Storm Risk

With 50,000 active users, Meshtastic's flood-based routing would create significant congestion:

  • Each message potentially propagates to every node within hop limits
  • With default settings, congestion scaling would help but might not be sufficient

Resource Utilization

Packet Pool Definition
#define MAX_RX_FROMRADIO 4 // max number of packets destined to our queue
#define MAX_PACKETS (MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + 2) // max number of packets in flight
  • Packet pool size is limited and could be quickly exhausted
  • Under heavy load, oldest packets would be dropped from queues

Congestion Control

  • Meshtastic implements hop limits (typically 3-7 hops)
  • Role-based prioritization helps critical nodes like ROUTER maintain function
  • Less effective at discarding unnecessary retransmissions

MeshCore Network Capacity

Selective Forwarding

Seen Packet Tracking
bool hasSeen(const mesh::Packet* packet) override {
  if (packet->getPayloadType() == PAYLOAD_TYPE_ACK) {
    uint32_t ack;
    memcpy(&ack, packet->payload, 4);
    for (int i = 0; i < MAX_PACKET_ACKS; i++) {
      if (ack == _acks[i]) { 
        if (packet->isRouteDirect()) {
          _direct_dups++;   // keep some stats
        } else {
          _flood_dups++;
        }
        return true;
      }
    }
    // Add to seen table...
  }
  // More implementation...
}

Only forwards packets that are specifically destined via that node:

  • Significantly reduces network-wide traffic compared to flooding
  • Well-suited for dense node deployments

Prioritization System

  • Assigns higher priority to direct messages (pri=0) over flood messages (pri=1-3)
  • Assigns decreasing priority as messages propagate further from source

Airtime Management

  • Limits each node to approximately 33% airtime utilization
  • Implements randomized retransmission delays to prevent collisions

Performance Predictions for 300km² with 1K Nodes

Meshtastic Performance

Message Propagation

  • With configured hop limits, messages would reach approximately 7-10km radius
  • Nodes would need to be positioned within 1-2km of each other for reliable coverage
  • Would require strategic node placement for full coverage

Broadcast Efficiency

  • High redundancy ensures messages reach destinations if any path exists
  • At 50K users sending messages, network would likely experience significant congestion
  • Congestion scaling would increase intervals between broadcast messages

Scalability Concerns

  • Duplicate detection tables are limited in size
  • As traffic increases, ability to track duplicates decreases
  • Likely to experience significant packet loss at peak usage

MeshCore Performance

Message Propagation

  • Direct routing requires established paths
  • Initial network formation would rely on announce packets
  • With 1K strategically placed nodes, path discovery may take time but would be more efficient

Traffic Management

  • Selective forwarding means significantly less network congestion
  • Room servers could act as regional message collection points
  • Airtime limiting prevents any single node from overwhelming the network

Scalability Strengths

  • Priority system gives preference to direct routed packets
  • Random delays prevent collision storms after regional events
  • Decreasing priority with distance prevents distant nodes from consuming bandwidth

Optimizations for Disaster Scenarios

Optimizing Meshtastic

  1. Increase Router Density: Deploy more router/repeater nodes with strategic placement
  2. Reduce Default Hop Limit: Consider reducing from default 3-7 to 2-3 hops
  3. Strengthen Congestion Scaling: More aggressive scaling at high node counts
  4. Implement Priority-Based Queuing: Critical messages should have transmission priority

Optimizing MeshCore

  1. Pre-established Room Servers: Deploy room servers at strategic locations
  2. Optimize Announce Intervals: Reduce announce frequency in high-density areas
  3. Increase Path Discovery Proactivity: More aggressive path discovery for critical routes
  4. Adjust Airtime Budget: Consider reducing below 33% in high-density areas

Technical Conclusion

In a large-scale disaster scenario with 50,000 users across 1,000 nodes in 300 km²:

Meshtastic would provide more immediate message propagation through its aggressive flooding mechanism, but would likely suffer from significant congestion and packet loss. It would perform best in the immediate aftermath when node count is lower and redundancy is critical.

MeshCore would offer more sustainable communication over time through its selective routing and prioritization schemes. While initial path discovery might take longer, the network would maintain higher throughput once paths are established, especially with strategic room server placement.

For maximum resilience, a hybrid deployment could leverage Meshtastic's flooding for critical emergency messages and MeshCore's selective routing for sustained communication channels.