mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-23 15:02:27 +00:00
2a2f8d752f
Indeed the core of the overlay mesh is now in place and nodes on simple meshes discover each other. Plenty of bugs are sure to remain.
209 lines
6.9 KiB
C
209 lines
6.9 KiB
C
#include "mphlr.h"
|
|
|
|
/* List of prioritised advertisements */
|
|
#define OVERLAY_MAX_ADVERTISEMENT_REQUESTS 16
|
|
overlay_node *oad_requests[OVERLAY_MAX_ADVERTISEMENT_REQUESTS];
|
|
int oad_request_count=0;
|
|
|
|
/* Where we are up to in the node list for round-robin advertising */
|
|
int oad_bin=0;
|
|
int oad_slot=0;
|
|
|
|
/* Which round of the node list we are up to.
|
|
This is used for reducing the advertisement rate for stable nodes.
|
|
Initially this will just mean advertising higher-scoring nodes
|
|
less often.
|
|
|
|
Our goal is to advertise all nodes often enough to maintain connectivity,
|
|
without wasting any packets.
|
|
|
|
Basically high-scoring nodes can be advertised less often than low-scoring
|
|
nodes.
|
|
|
|
Let's advertise nodes <100 every round, <200 every 2 rounds, and >=200
|
|
every 4th round.
|
|
*/
|
|
int oad_round=0;
|
|
|
|
/* Request that this node be advertised as a matter of priority */
|
|
int overlay_route_please_advertise(overlay_node *n)
|
|
{
|
|
if (oad_request_count<OVERLAY_MAX_ADVERTISEMENT_REQUESTS)
|
|
{
|
|
oad_requests[oad_request_count++]=n;
|
|
return 0;
|
|
}
|
|
else return 1;
|
|
}
|
|
|
|
int overlay_route_add_advertisements(int interface,overlay_buffer *e)
|
|
{
|
|
/* Construct a route advertisement frame and append it to e.
|
|
|
|
Work out available space in packet for advertisments, and fit the
|
|
highest scoring nodes from the current portion in.
|
|
|
|
Each advertisement consists of an address prefix followed by score.
|
|
We will use 6 bytes of prefix to make it reasonably hard to generate
|
|
collisions, including by birthday paradox (good for networks upto about
|
|
20million nodes), and one byte each for score gateways_en_route.
|
|
|
|
XXX - We need to send full addresses sometimes so that receiver can
|
|
resolve them. Either that or we need to start supporting the PLEASEEXPLAIN
|
|
packets, which is probably a better solution.
|
|
|
|
The receiver will discount the score based on their measured reliability
|
|
for packets to arrive from us; we just repeat what discounted score
|
|
we have remembered.
|
|
|
|
Hacking the frame together this way is less flexible, but much faster
|
|
than messing about with malloc() and setting address fields.
|
|
|
|
The src,dst and nexthop can each be encoded with a single byte.
|
|
Thus using a fixed 1-byte RFS field we are limited to RFS<0xfa,
|
|
which gives us 30 available advertisement slots per packet.
|
|
*/
|
|
int i;
|
|
int bytes=e->sizeLimit-e->length;
|
|
int overhead=1+1+3+32+1+1; /* maximum overhead */
|
|
int slots=(bytes-overhead)/8;
|
|
if (slots>30) slots=30;
|
|
int slots_used=0;
|
|
|
|
if (slots<1) return WHY("No room for node advertisements");
|
|
|
|
if (ob_append_byte(e,OF_TYPE_NODEANNOUNCE))
|
|
return WHY("could not add node advertisement header");
|
|
ob_append_byte(e,1); /* TTL */
|
|
int rfs_offset=e->length; /* remember where the RFS byte gets stored
|
|
so that we can patch it later */
|
|
ob_append_byte(e,1+1+1+8*slots_used/* RFS */);
|
|
|
|
/* Stuff in dummy address fields */
|
|
ob_append_byte(e,OA_CODE_BROADCAST);
|
|
ob_append_byte(e,OA_CODE_BROADCAST);
|
|
ob_append_byte(e,OA_CODE_SELF);
|
|
|
|
int count;
|
|
while (slots>0&&oad_request_count) {
|
|
oad_request_count--;
|
|
ob_append_bytes(e,oad_requests[oad_request_count]->sid,6);
|
|
ob_append_byte(e,oad_requests[oad_request_count]->best_link_score);
|
|
ob_append_byte(e,oad_requests[oad_request_count]
|
|
->observations[oad_requests[oad_request_count]
|
|
->best_observation].gateways_en_route);
|
|
slots--;
|
|
slots_used++;
|
|
}
|
|
|
|
while(slots>0)
|
|
{
|
|
/* find next node */
|
|
int bin=oad_bin;
|
|
int slot=oad_slot;
|
|
|
|
/* XXX Skipping priority advertised nodes could be done faster, e.g.,
|
|
by adding a flag to the overlay_node structure to indicate if it
|
|
has been sent priority, and if so, skip it.
|
|
The flags could then be reset at the end of this function.
|
|
But this will do for now.
|
|
*/
|
|
int skip=0;
|
|
for(i=0;i<count;i++)
|
|
if (oad_requests[i]==&overlay_nodes[oad_bin][oad_slot])
|
|
skip=1;
|
|
|
|
if (!skip)
|
|
{
|
|
if(overlay_nodes[oad_bin][oad_slot].sid[0]) {
|
|
overlay_node *n=&overlay_nodes[oad_bin][oad_slot];
|
|
|
|
ob_append_bytes(e,n->sid,6);
|
|
ob_append_byte(e,n->best_link_score);
|
|
ob_append_byte(e,n->observations[n->best_observation].gateways_en_route);
|
|
|
|
slots--;
|
|
slots_used++;
|
|
}
|
|
}
|
|
|
|
/* Find next node */
|
|
oad_slot++;
|
|
if (oad_slot>=overlay_bin_size) { oad_slot=0; oad_bin++; }
|
|
|
|
/* Stop stuffing if we get to the end of the node list so that
|
|
we can implement an appropriate pause between rounds to avoid
|
|
unneeded repeated TX of nodes. */
|
|
if (oad_bin>=overlay_bin_count) { oad_bin=0; oad_round++; break; }
|
|
|
|
/* Stop if we have advertised everyone */
|
|
if (oad_bin==bin&&oad_slot==slot) break;
|
|
}
|
|
|
|
e->bytes[rfs_offset]=1+1+1+8*slots_used;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Pull out the advertisements and update our routing table accordingly.
|
|
Because we are using a non-standard abbreviation scheme, we have to extract
|
|
and search for the nodes ourselves.
|
|
|
|
Also, we need to discount the scores based on the score of the sender.
|
|
We can either do this once now (more computationally efficient), or have
|
|
a rather complicated scheme whereby we attempt to trace through the list
|
|
of nodes from here to there. That seems silly, and is agains't the BATMAN
|
|
approach of each node just knowing single-hop information.
|
|
*/
|
|
int overlay_route_saw_advertisements(int i,overlay_frame *f, long long now)
|
|
{
|
|
int ofs=0;
|
|
|
|
/* lookup score of current sender */
|
|
overlay_node *sender=overlay_route_find_node(f->source,0);
|
|
int sender_score=sender->best_link_score;
|
|
fprintf(stderr,"score to reach %s is %d\n",
|
|
overlay_render_sid(f->source),sender_score);
|
|
|
|
while(ofs<f->payload->length)
|
|
{
|
|
unsigned char to[SID_SIZE];
|
|
int out_len=0;
|
|
int r
|
|
=overlay_abbreviate_cache_lookup(&f->payload->bytes[ofs],to,&out_len,
|
|
6 /* prefix length */,
|
|
0 /* no index code to process */);
|
|
int score=f->payload->bytes[6];
|
|
int gateways_en_route=f->payload->bytes[7];
|
|
|
|
|
|
/* Don't let nodes advertise paths to themselves!
|
|
(paths to self get detected through selfannouncements and selfannouncement acks) */
|
|
if (memcmp(&overlay_abbreviate_current_sender.b[0],to,SID_SIZE))
|
|
{
|
|
/* Discount score by score to sender */
|
|
score*=sender_score;
|
|
score=score>>8;
|
|
|
|
if (r==OA_RESOLVED) {
|
|
/* File it */
|
|
overlay_route_record_link(now,to,&overlay_abbreviate_current_sender.b[0],
|
|
time(0) /* XXX should this be in senders timeframe?
|
|
Should we be sending time stamps around
|
|
so that we know when the last actual
|
|
sighting of a node really was?
|
|
(probably a waste of time since we decay
|
|
scores from stale observations) */,
|
|
score,gateways_en_route);
|
|
} else if (r==OA_PLEASEEXPLAIN) {
|
|
/* Unresolved address -- ask someone to resolve it for us. */
|
|
WHY("Dispatch PLEASEEXPLAIN not implemented");
|
|
}
|
|
}
|
|
|
|
ofs+=8;
|
|
}
|
|
|
|
return 0;
|
|
}
|