Use the hop_limit field of MeshPacket to limit max delivery depth in

the mesh.
1.2-legacy
geeksville 2020-05-18 17:35:23 -07:00
rodzic 53c3d9baa2
commit 26d3ef529e
9 zmienionych plików z 51 dodań i 33 usunięć

Wyświetl plik

@ -1,12 +1,10 @@
# Mesh broadcast algorithm
FIXME - instead look for standard solutions. this approach seems really suboptimal, because too many nodes will try to rebroast. If
all else fails could always use the stock Radiohead solution - though super inefficient.
great source of papers and class notes: http://www.cs.jhu.edu/~cs647/
reliable messaging tasks (stage one for DSR):
- fix FIXME - should snoop packet not sent to us
- add a 'messagePeek' hook for all messages that pass through our node.
- DONE use the same 'recentmessages' array used for broadcast msgs to detect duplicate retransmitted messages.
- keep possible retries in the list with to be rebroadcast messages?
@ -14,7 +12,6 @@ reliable messaging tasks (stage one for DSR):
- delay some random time for each retry (large enough to allow for acks to come in)
- once an ack comes in, remove the packet from the retry list and deliver the ack to the original sender
- after three retries, deliver a no-ack packet to the original sender (i.e. the phone app or mesh router service)
- add a max hops parameter, use it for broadcast as well (0 means adjacent only, 1 is one forward etc...). Store as three bits in the header.
dsr tasks
@ -55,6 +52,8 @@ when we receive a routeError packet
TODO:
- optimize our generalized flooding with heuristics, possibly have particular nodes self mark as 'router' nodes.
- DONE reread the radiohead mesh implementation - hop to hop acknowledgement seems VERY expensive but otherwise it seems like DSR
- DONE read about mesh routing solutions (DSR and AODV)
- DONE read about general mesh flooding solutions (naive, MPR, geo assisted)
@ -62,6 +61,7 @@ TODO:
- REJECTED - seems dying - possibly dash7? https://www.slideshare.net/MaartenWeyn1/dash7-alliance-protocol-technical-presentation https://github.com/MOSAIC-LoPoW/dash7-ap-open-source-stack - does the opensource stack implement multihop routing? flooding? their discussion mailing list looks dead-dead
- update duty cycle spreadsheet for our typical usecase
- DONE generalize naive flooding
- DONE add a max hops parameter, use it for broadcast as well (0 means adjacent only, 1 is one forward etc...). Store as three bits in the header.
a description of DSR: https://tools.ietf.org/html/rfc4728 good slides here: https://www.slideshare.net/ashrafmath/dynamic-source-routing
good description of batman protocol: https://www.open-mesh.org/projects/open-mesh/wiki/BATMANConcept

2
proto

@ -1 +1 @@
Subproject commit bc3ecd97e381b724c1a28acce0d12c688de73ba3
Subproject commit 5799cb10b8f3cf353e7791d0609002cc93d9d13d

Wyświetl plik

@ -2,8 +2,6 @@
#include "configuration.h"
#include "mesh-pb-constants.h"
static bool supportFlooding = true; // Sometimes to simplify debugging we want jusT simple broadcast only
FloodingRouter::FloodingRouter() : toResend(MAX_NUM_NODES) {}
/**
@ -13,9 +11,7 @@ FloodingRouter::FloodingRouter() : toResend(MAX_NUM_NODES) {}
*/
ErrorCode FloodingRouter::send(MeshPacket *p)
{
// We update our table of recent broadcasts, even for messages we send
if (supportFlooding)
wasSeenRecently(p);
wasSeenRecently(p);
return Router::send(p);
}
@ -29,28 +25,28 @@ ErrorCode FloodingRouter::send(MeshPacket *p)
*/
void FloodingRouter::handleReceived(MeshPacket *p)
{
if (supportFlooding) {
if (wasSeenRecently(p)) {
DEBUG_MSG("Ignoring incoming floodmsg, because we've already seen it\n");
packetPool.release(p);
} else {
if (p->to == NODENUM_BROADCAST) {
if (p->id != 0) {
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
if (wasSeenRecently(p)) {
DEBUG_MSG("Ignoring incoming msg, because we've already seen it\n");
packetPool.release(p);
} else {
if (p->to == NODENUM_BROADCAST && p->hop_limit > 0) {
if (p->id != 0) {
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
DEBUG_MSG("Rebroadcasting received floodmsg to neighbors, fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
// Note: we are careful to resend using the original senders node id
// We are careful not to call our hooked version of send() - because we don't want to check this again
Router::send(tosend);
tosend->hop_limit--; // bump down the hop count
} else {
DEBUG_MSG("Ignoring a simple (0 hop) broadcast\n");
}
DEBUG_MSG("Rebroadcasting received floodmsg to neighbors, fr=0x%x,to=0x%x,id=%d,hop_limit=%d\n", p->from, p->to,
p->id, tosend->hop_limit);
// Note: we are careful to resend using the original senders node id
// We are careful not to call our hooked version of send() - because we don't want to check this again
Router::send(tosend);
} else {
DEBUG_MSG("Ignoring a simple (0 id) broadcast\n");
}
// handle the packet as normal
Router::handleReceived(p);
}
} else
// handle the packet as normal
Router::handleReceived(p);
}
}

Wyświetl plik

@ -285,6 +285,7 @@ MeshPacket *MeshService::allocForSending()
p->which_payload = MeshPacket_decoded_tag; // Assume payload is decoded at start.
p->from = nodeDB.getNodeNum();
p->to = NODENUM_BROADCAST;
p->hop_limit = HOP_MAX;
p->id = generatePacketId();
p->rx_time = getValidTime(); // Just in case we process the packet locally - make sure it has a valid timestamp

Wyświetl plik

@ -14,6 +14,15 @@ typedef uint8_t PacketId; // A packet sequence number
#define ERRNO_NO_INTERFACES 33
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
/**
* the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket.
*
* We reserve 3 bits in the header so this could be up to 7, but given the high range of lora and typical usecases, keeping
* maxhops to 3 should be fine for a while. This also serves to prevent routing/flooding attempts to be attempted for
* too long.
**/
#define HOP_MAX 3
typedef int ErrorCode;
/// Alloc and free packets to our global, ISR safe pool

Wyświetl plik

@ -115,8 +115,9 @@ size_t RadioInterface::beginSending(MeshPacket *p)
h->from = p->from;
h->to = p->to;
h->flags = 0;
h->id = p->id;
assert(p->hop_limit <= HOP_MAX);
h->flags = p->hop_limit;
// if the sender nodenum is zero, that means uninitialized
assert(h->from);

Wyświetl plik

@ -16,7 +16,14 @@
* wtih the old radiohead implementation.
*/
typedef struct {
uint8_t to, from, id, flags;
uint8_t to, from, id;
/**
* Usage of flags:
*
* The bottom three bits of flags are use to store hop_limit when sent over the wire.
**/
uint8_t flags;
} PacketHeader;
typedef enum {

Wyświetl plik

@ -288,13 +288,16 @@ void RadioLibInterface::handleReceiveInterrupt()
rxGood++;
if (h->to != 255 && h->to != ourAddr) {
DEBUG_MSG("ignoring packet not sent to us\n");
DEBUG_MSG("FIXME - should snoop packet not sent to us\n");
} else {
MeshPacket *mp = packetPool.allocZeroed();
mp->from = h->from;
mp->to = h->to;
mp->id = h->id;
assert(HOP_MAX <= 0x07); // If hopmax changes, carefully check this code
mp->hop_limit = h->flags & 0x07;
addReceiveMetadata(mp);
mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point

Wyświetl plik

@ -59,7 +59,8 @@ class Router
* Handle any packet that is received by an interface on this node.
* Note: some packets may merely being passed through this node and will be forwarded elsewhere.
*
* Note: this method will free the provided packet
* Note: this packet will never be called for messages sent/generated by this node.
* Note: this method will free the provided packet.
*/
virtual void handleReceived(MeshPacket *p);
};