Refactor routing node information to use new subscriber tree

This commit is contained in:
Jeremy Lakeman 2012-08-15 13:36:10 +09:30
parent 30d5ed2b6d
commit aa5706f9d7
13 changed files with 390 additions and 862 deletions

View File

@ -1704,8 +1704,9 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
}
cli_printf("record"); cli_delim(":");
cli_printf("%d",mdp.nodeinfo.index); cli_delim(":");
cli_printf("%d",mdp.nodeinfo.count); cli_delim(":");
// TODO remove these two unused output fields
cli_printf("%d",1); cli_delim(":");
cli_printf("%d",1); cli_delim(":");
cli_printf("%s",mdp.nodeinfo.foundP?"found":"noresult"); cli_delim(":");
cli_printf("%s", alloca_tohex_sid(mdp.nodeinfo.sid)); cli_delim(":");
cli_printf("%s",mdp.nodeinfo.resolve_did?mdp.nodeinfo.did:"did-not-resolved");

View File

@ -248,8 +248,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define COMPUTE_RFS_LENGTH -1
#define OVERLAY_SENDER_PREFIX_LENGTH 12
/* Keep track of last 32 observations of a node.
Hopefully this is enough, if not, we will increase.
To keep the requirement down we will collate contigious neighbour observations on each interface.

View File

@ -409,28 +409,10 @@ int monitor_process_command(struct monitor_context *c)
else if (sscanf(cmd,"lookup match %s %d %s %s",sid,&port,localDid,remoteDid)>=3) {
monitor_send_lookup_response(sid,port,localDid,remoteDid);
}else if (sscanf(cmd,"call %s %s %s",sid,localDid,remoteDid)==3) {
int gotSid = 0;
if (sid[0]=='*') {
/* For testing, pick any peer and call them */
int bin, slot;
for (bin = 0; bin < overlay_bin_count; bin++)
for (slot = 0; slot < overlay_bin_size; slot++) {
if (overlay_nodes[bin][slot].sid[0]) {
memcpy(sid, overlay_nodes[bin][slot].sid, SID_SIZE);
gotSid = 1;
break;
}
}
if (!gotSid)
write_str(c->alarm.poll.fd,"\nERROR:no known peers, so cannot place call\n");
} else {
// pack the binary representation of the sid into the same buffer.
if (stowSid((unsigned char*)sid, 0, sid) == -1)
write_str(c->alarm.poll.fd,"\nERROR:invalid SID, so cannot place call\n");
else
gotSid = 1;
}
if (gotSid) {
else {
int cn=0, in=0, kp=0;
if (!keyring_next_identity(keyring, &cn, &in, &kp))
write_str(c->alarm.poll.fd,"\nERROR:no local identity, so cannot place call\n");

View File

@ -125,9 +125,6 @@ int overlayServerMode()
of wifi latency anyway, so we'll live with it. Larger values will affect voice transport,
and smaller values would affect CPU and energy use, and make the simulation less realistic. */
/* Create structures to use 1MB of RAM for testing */
overlay_route_init(1);
#define SCHEDULE(X, Y, D) { \
static struct sched_ent _sched_##X; \
static struct profile_total _stats_##X; \
@ -261,7 +258,7 @@ int overlay_frame_process(struct overlay_interface *interface,overlay_frame *f)
if (!broadcast)
{
if (overlay_get_nexthop(f->destination,f->nexthop,&f->nexthop_interface))
WHYF("Could not find next hop for %s* - dropping frame",
INFOF("Could not find next hop for %s* - dropping frame",
alloca_tohex(f->destination, 7));
forward=0;
}

View File

@ -156,8 +156,6 @@ sid overlay_abbreviate_previous_address={{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
it on most occassions.
*/
sid overlay_abbreviate_current_sender={{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
int overlay_abbreviate_current_sender_set=0;
int overlay_abbreviate_current_sender_id=-1;
int overlay_abbreviate_prepare_cache()
{
@ -266,7 +264,6 @@ int overlay_abbreviate_address(unsigned char *in,unsigned char *out,int *ofs)
if (in[0]<0x10) return WHY("Invalid address - 0x00-0x0f are reserved prefixes.");
/* Is this the same as the current sender? */
if (overlay_abbreviate_current_sender_set){
for(i=0;i<SID_SIZE;i++)
if (in[i]!=overlay_abbreviate_current_sender.b[i])
break;
@ -274,7 +271,6 @@ int overlay_abbreviate_address(unsigned char *in,unsigned char *out,int *ofs)
out[(*ofs)++]=OA_CODE_SELF;
return 0;
}
}
/* Try repeating previous address */
for(i=0;i<SID_SIZE;i++)
@ -369,7 +365,7 @@ int overlay_abbreviate_expand_address(unsigned char *in,int *inofs,unsigned char
DEBUGF("Address first byte/abbreviation code=%02x (input offset=%d)\n",in[*inofs],*inofs);
switch(in[*inofs])
{
case OA_CODE_02: case OA_CODE_04: case OA_CODE_0C:
case OA_CODE_02: case OA_CODE_04: case OA_CODE_0C: case OA_CODE_INDEX:
/* Unsupported codes, so tell the sender
if the frame was addressed to us as next-hop */
(*inofs)++;
@ -380,8 +376,9 @@ int overlay_abbreviate_expand_address(unsigned char *in,int *inofs,unsigned char
used to encode the sender's address there ;) */
(*inofs)++;
if (debug&DEBUG_OVERLAYABBREVIATIONS) DEBUGF("Resolving OA_CODE_SELF.\n");
if (overlay_abbreviate_current_sender_set) {
bcopy(&overlay_abbreviate_current_sender.b[0],&out[*ofs],SID_SIZE);
if (overlay_abbreviate_current_sender.b[0]) {
bcopy(overlay_abbreviate_current_sender.b,&out[*ofs],SID_SIZE);
overlay_abbreviate_set_most_recent_address(&out[*ofs]);
(*ofs)+=SID_SIZE;
return OA_RESOLVED;
@ -389,17 +386,6 @@ int overlay_abbreviate_expand_address(unsigned char *in,int *inofs,unsigned char
WARN("Cannot resolve OA_CODE_SELF if the packet doesn't start with a self announcement.\n");
return OA_UNINITIALISED;
}
case OA_CODE_INDEX: /* single byte index look up */
/* Lookup sender's neighbour ID */
if (overlay_abbreviate_current_sender_id == -1 && overlay_abbreviate_lookup_sender_id() == -1)
return WHY("could not lookup neighbour ID of packet sender");
r=overlay_abbreviate_cache_lookup(overlay_neighbours[overlay_abbreviate_current_sender_id].one_byte_index_address_prefixes[in[*inofs]],
out,ofs,OVERLAY_SENDER_PREFIX_LENGTH,0);
(*inofs)++;
if (r==OA_RESOLVED)
overlay_abbreviate_set_most_recent_address(&out[*ofs]);
(*inofs)++;
return r;
case OA_CODE_PREVIOUS: /* Same as last address */
(*inofs)++;
bcopy(&overlay_abbreviate_previous_address.b[0],&out[*ofs],SID_SIZE);
@ -448,7 +434,6 @@ int overlay_abbreviate_expand_address(unsigned char *in,int *inofs,unsigned char
if (in[*inofs]==OA_CODE_FULL_INDEX2) bytes=2;
if (bytes) (*inofs)++; /* Skip leading control code if present */
bcopy(&in[*inofs],&out[*ofs],SID_SIZE);
if (bytes) overlay_abbreviate_remember_index(bytes,&in[*inofs],&in[(*inofs)+SID_SIZE]);
overlay_abbreviate_cache_address(&in[*inofs]);
overlay_abbreviate_set_most_recent_address(&in[*inofs]);
(*inofs)+=SID_SIZE+bytes;
@ -456,37 +441,6 @@ int overlay_abbreviate_expand_address(unsigned char *in,int *inofs,unsigned char
}
}
int overlay_abbreviate_lookup_sender_id()
{
if (!overlay_abbreviate_current_sender_set)
return WHY("Sender has not been set");
overlay_neighbour *neh=overlay_route_get_neighbour_structure(overlay_abbreviate_current_sender.b,SID_SIZE,1 /* create if needed */);
if (!neh) { overlay_abbreviate_current_sender_id=-1; return WHY("Could not find sender in neighbour list"); }
/* Okay, so the following is a little tortuous in asking our parent who we are instead of just knowing,
but it will do for now */
if (!neh->node) return WHY("neighbour structure has no associated node");
overlay_abbreviate_current_sender_id=neh->node->neighbour_id;
return 0;
}
int overlay_abbreviate_remember_index(int index_byte_count,unsigned char *sid_to_remember,unsigned char *index_bytes)
{
int index=index_bytes[0];
if (index_byte_count>1) index=(index<<8)|index_bytes[1];
/* Lookup sender's neighbour ID */
if (overlay_abbreviate_current_sender_id == -1 && overlay_abbreviate_lookup_sender_id() == -1)
return WHY("could not lookup neighbour ID of packet sender");
if (debug&DEBUG_OVERLAYABBREVIATIONS) {
DEBUGF("index=%d", index);
DEBUGF("remember that sender #%d has assigned index #%d to sid=[%s]", overlay_abbreviate_current_sender_id, index, alloca_tohex_sid(sid_to_remember));
}
bcopy(sid_to_remember,overlay_neighbours[overlay_abbreviate_current_sender_id].one_byte_index_address_prefixes[index],OVERLAY_SENDER_PREFIX_LENGTH);
return 0;
}
int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *ofs,
int prefix_bytes,int index_bytes)
{
@ -546,13 +500,6 @@ int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *of
bcopy(&cache->sids[index].b[0],&out[(*ofs)],SID_SIZE);
(*ofs)+=SID_SIZE;
if (index_bytes) {
/* We need to remember it as well, so do that.
If this process fails, it is okay, as we can still resolve the address now.
It will probably result in waste later though when we get asked to look it up,
however the alternative definitely wastes bandwidth now, so let us defer the
corrective action in case it is never required.
*/
overlay_abbreviate_remember_index(index_bytes,&cache->sids[index].b[0],&in[prefix_bytes]);
(*ofs)+=index_bytes;
}
if (debug&DEBUG_OVERLAYABBREVIATIONS)
@ -564,14 +511,12 @@ int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *of
int overlay_abbreviate_set_current_sender(unsigned char *in)
{
bcopy(in,&overlay_abbreviate_current_sender.b[0],SID_SIZE);
overlay_abbreviate_current_sender_id=-1;
overlay_abbreviate_current_sender_set=1;
return 0;
}
int overlay_abbreviate_unset_current_sender()
{
overlay_abbreviate_current_sender_set=0;
overlay_abbreviate_current_sender.b[0]=0;
return 0;
}

View File

@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
#include "subscribers.h"
/* List of prioritised advertisements */
#define OVERLAY_MAX_ADVERTISEMENT_REQUESTS 16
@ -55,6 +56,34 @@ int overlay_route_please_advertise(overlay_node *n)
else return 1;
}
struct subscriber *last_advertised=NULL;
int add_advertisement(struct subscriber *subscriber, void *context){
overlay_buffer *e=context;
if (subscriber->node){
overlay_node *n=subscriber->node;
ob_append_bytes(e,subscriber->sid,6);
ob_append_byte(e,n->best_link_score);
ob_append_byte(e,n->observations[n->best_observation].gateways_en_route);
// stop if we run out of space
if (ob_makespace(e,8)!=0){
last_advertised=subscriber;
return 1;
}
// or we've been called twice and looped around
if (subscriber == last_advertised){
last_advertised = NULL;
return 1;
}
}
return 0;
}
int overlay_route_add_advertisements(overlay_buffer *e)
{
/* Construct a route advertisement frame and append it to e.
@ -83,19 +112,13 @@ int overlay_route_add_advertisements(overlay_buffer *e)
which gives us 30 available advertisement slots per packet.
*/
int i;
int bytes=e->sizeLimit-e->length;
int overhead=1+8+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 */
ob_append_rfs(e,1+8+1+1+8*slots_used);
// assume we might fill the packet
ob_append_rfs(e, e->sizeLimit - e->length);
/* Stuff in dummy address fields */
ob_append_byte(e,OA_CODE_BROADCAST);
@ -105,9 +128,11 @@ int overlay_route_add_advertisements(overlay_buffer *e)
overlay_abbreviate_clear_most_recent_address();
overlay_abbreviate_append_address(e, overlay_get_my_sid());
// TODO high priority advertisements first....
/*
while (slots>0&&oad_request_count) {
oad_request_count--;
ob_append_bytes(e,oad_requests[oad_request_count]->sid,6);
ob_append_bytes(e,oad_requests[oad_request_count]->subscriber->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]
@ -115,49 +140,15 @@ int overlay_route_add_advertisements(overlay_buffer *e)
slots--;
slots_used++;
}
*/
struct subscriber *start = last_advertised;
while(slots>0)
{
/* find next node */
int bin=oad_bin;
int slot=oad_slot;
// append announcements starting from the last node we advertised
enum_subscribers(start, add_advertisement, e);
/* 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<oad_request_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;
// if we didn't start at the beginning and still have space, start again from the beginning
if (start && e->sizeLimit - e->length >=8){
enum_subscribers(NULL, add_advertisement, e);
}
ob_patch_rfs(e,COMPUTE_RFS_LENGTH);
@ -178,62 +169,46 @@ int overlay_route_add_advertisements(overlay_buffer *e)
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, SID_SIZE, 0);
if (sender == NULL) {
WARNF("Cannot advertise %s -- overlay node not found", alloca_tohex_sid(f->source));
return -1;
}
int sender_score=sender->best_link_score;
if (debug&DEBUG_OVERLAYROUTEMONITOR)
DEBUGF("score to reach %s is %d", alloca_tohex_sid(f->source),sender_score);
IN();
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 */);
if (r==OA_PLEASEEXPLAIN) {
/* Unresolved address -- TODO ask someone to resolve it for us. */
WARN("Dispatch PLEASEEXPLAIN not implemented");
struct subscriber *subscriber;
subscriber = find_subscriber(&f->payload->bytes[ofs], 6, 0);
if (!subscriber){
//WARN("Dispatch PLEASEEXPLAIN not implemented");
goto next;
}
int score=f->payload->bytes[6];
int gateways_en_route=f->payload->bytes[7];
int score=f->payload->bytes[ofs+6];
int gateways_en_route=f->payload->bytes[ofs+7];
/* Don't record routes to ourselves */
if (overlay_address_is_local(to)) {
if (overlay_address_is_local(subscriber->sid)) {
if (debug & DEBUG_OVERLAYROUTING)
DEBUGF("Ignore announcement about me (%s)", alloca_tohex_sid(to));
DEBUGF("Ignore announcement about me (%s)", alloca_tohex_sid(subscriber->sid));
goto next;
}
/* 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)){
if (!memcmp(overlay_abbreviate_current_sender.b,subscriber->sid,SID_SIZE)){
if (debug & DEBUG_OVERLAYROUTING)
DEBUGF("Ignore announcement about neighbour (%s)", alloca_tohex_sid(to));
DEBUGF("Ignore announcement about neighbour (%s)", alloca_tohex_sid(subscriber->sid));
goto next;
}
if (r==OA_RESOLVED) {
/* File it */
overlay_route_record_link(now,to,&overlay_abbreviate_current_sender.b[0],
overlay_route_record_link(now,subscriber->sid,overlay_abbreviate_current_sender.b,
i,
/* time range that this advertisement covers.
XXX - Make it up for now. */
now-2500,now,
score,gateways_en_route);
}
next:
ofs+=8;
}
return 0;
RETURN(0);;
}

View File

@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <sys/stat.h>
#include "serval.h"
#include "strbuf.h"
#include "subscribers.h"
struct profile_total mdp_stats={.name="overlay_mdp_poll"};
@ -937,6 +938,29 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
}
}
struct search_state{
overlay_mdp_frame *mdp;
overlay_mdp_frame *mdpreply;
int first;
int max;
int index;
int count;
};
int search_subscribers(struct subscriber *subscriber, void *context){
struct search_state *state = context;
if (!subscriber->node)
return 0;
int score = subscriber->node->best_link_score;
if (state->mdp->addrlist.mode == MDP_ADDRLIST_MODE_ALL_PEERS || score >= 1) {
if (state->count++ >= state->first && state->index < state->max) {
memcpy(state->mdpreply->addrlist.sids[state->index++], subscriber->sid, SID_SIZE);
}
}
return 0;
}
void overlay_mdp_poll(struct sched_ent *alarm)
{
unsigned char buffer[16384];
@ -1014,27 +1038,16 @@ void overlay_mdp_poll(struct sched_ent *alarm)
case MDP_ADDRLIST_MODE_ROUTABLE_PEERS:
case MDP_ADDRLIST_MODE_ALL_PEERS: {
/* from peer list */
i = count = 0;
int bin, slot;
for (bin = 0; bin < overlay_bin_count; ++bin) {
for (slot = 0; slot < overlay_bin_size; ++slot) {
const unsigned char *sid = overlay_nodes[bin][slot].sid;
if (sid[0]) {
const char *sidhex = alloca_tohex_sid(sid);
int score = overlay_nodes[bin][slot].best_link_score;
if (debug & DEBUG_MDPREQUESTS)
DEBUGF("bin=%d slot=%d sid=%s best_link_score=%d", bin, slot, sidhex, score);
if (mdp->addrlist.mode == MDP_ADDRLIST_MODE_ALL_PEERS || score >= 1) {
if (count++ >= sid_num && i < max_sids) {
if (debug & DEBUG_MDPREQUESTS) DEBUGF("send sid=%s", sidhex);
memcpy(mdpreply.addrlist.sids[i++], sid, SID_SIZE);
} else {
if (debug & DEBUG_MDPREQUESTS) DEBUGF("skip sid=%s", sidhex);
}
}
}
}
}
struct search_state state={
.mdp=mdp,
.mdpreply=&mdpreply,
.first=sid_num,
.max=max_sid,
};
enum_subscribers(NULL, search_subscribers, &state);
i=state.index;
count=state.count;
}
break;
}

View File

@ -213,11 +213,8 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
DEBUG(strbuf_str(b));
}
if (f.nexthop[0]==0 || f.destination[0]==0 || f.source[0]==0){
WHY("Addresses expanded incorrectly");
dump(NULL, &packet[payloadStart], ofs - payloadStart);
if (f.nexthop[0]==0 || f.destination[0]==0 || f.source[0]==0)
break;
}
if (nexthop_address_status!=OA_RESOLVED
|| destination_address_status!=OA_RESOLVED
@ -236,6 +233,11 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
break;
}else{
/* Record current sender for reference by addresses in subsequent frames in the
ensemble */
if (f.type==OF_TYPE_SELFANNOUNCE)
overlay_abbreviate_set_current_sender(f.source);
// TODO refactor all packet parsing to only allocate additional memory for the payload
// if it needs to be queued for forwarding.

View File

@ -315,20 +315,6 @@ overlay_frame *op_dup(overlay_frame *in)
return out;
}
int overlay_frame_set_neighbour_as_source(overlay_frame *f,overlay_neighbour *n)
{
if (!n) return WHY("Neighbour was null");
bcopy(n->node->sid,f->source,SID_SIZE);
return 0;
}
int overlay_frame_set_neighbour_as_destination(overlay_frame *f,overlay_neighbour *n)
{
if (!n) return WHY("Neighbour was null");
bcopy(n->node->sid,f->destination,SID_SIZE);
return 0;
}
int overlay_frame_set_broadcast_as_destination(overlay_frame *f)
{
overlay_broadcast_generate_address(f->destination);

View File

@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "strbuf.h"
#include "subscribers.h"
/*
Here we implement the actual routing algorithm which is heavily based on BATMAN.
@ -121,230 +122,52 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* For fast handling we will have a number of bins that will be indexed by the
first few bits of the peer's SIDs, and a number of entries in each bin to
handle hash collissions while still allowing us to have static memory usage. */
int overlay_bin_count=0;
int overlay_bin_size=0; /* associativity, i.e., entries per bin */
int overlay_bin_bytes=0; /* number of bytes required to represent the range
[0..bin_count) */
overlay_node **overlay_nodes=NULL;
struct overlay_neighbour_observation {
/* Sequence numbers are handled as ranges because the tick
rate can vary between interfaces, and we want to be able to
estimate the reliability of links to nodes that may have
several available interfaces.
We don't want sequence numbers to wrap too often, but we
would also like to support fairly fast ticking interfaces,
e.g., for gigabit type links. So lets go with 1ms granularity. */
unsigned int s1;
unsigned int s2;
time_ms_t time_ms;
unsigned char sender_interface;
unsigned char valid;
};
/* We also need to keep track of which nodes are our direct neighbours.
struct overlay_neighbour {
time_ms_t last_observation_time_ms;
time_ms_t last_metric_update;
int most_recent_observation_id;
struct overlay_neighbour_observation observations[OVERLAY_MAX_OBSERVATIONS];
overlay_node *node;
/* Scores of visibility from each of the neighbours interfaces.
This is so that the sender knows which interface to use to reach us.
*/
unsigned char scores[OVERLAY_MAX_INTERFACES];
};
/* We need to keep track of which nodes are our direct neighbours.
This means we need to keep an eye on how recently we received DIRECT announcements
from nodes, and keep a list of the most recent ones. The challenge is to keep the
list ordered without having to do copies or have nasty linked-list structures that
require lots of random memory reads to resolve.
The simplest approach is to maintain a large cache of neighbours and practise random
The simplest approach is to maintain a cache of neighbours and practise random
replacement. It is however succecptible to cache flushing attacks by adversaries, so
we will need something smarter in the long term.
*/
int overlay_max_neighbours=0;
#define overlay_max_neighbours 128
int overlay_neighbour_count=0;
overlay_neighbour *overlay_neighbours=NULL;
struct overlay_neighbour overlay_neighbours[overlay_max_neighbours];
/* allocate structures according to memory availability.
We size differently because some devices are very constrained,
e.g., mesh potatoes, some are middle sized, like mobile phones, and
some are very large, like dedicated servers, that can keep track of
very many nodes.
int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now);
int overlay_route_recalc_neighbour_metrics(struct overlay_neighbour *n, time_ms_t now);
struct overlay_neighbour *overlay_route_get_neighbour_structure(overlay_node *node, int createP);
The memory allocation is in two main areas:
1. Neighbour list, which is short, requiring just a single pointer per
direct neighbour. So this can probably be set to a fairly large value
on any sized machine, certainly in the thousands, which should be more
than sufficient for wifi-type interfaces. 1000 neighbours requires
onlt 8KB on a 64 bit machine, which is probably a reasonable limit per
MB allocated. This leaves 1016KB/MB for:
2. The node information (overlay_node) structures. These take more
space and have to be sized appropriately. We also need to choose the
associativity of the node table based on the size of the structure.
The smaller the structure the greater the associativity we should have
so that the fewer the entries the more effectively we use them. The
trade-off is that increased associativity results in increased search
time as the bins are searched for matches. This is also why for very
large tables we want low associativity so that we are more CPU efficient.
The bulk of the size ofthe overlay_node structure is the observations
information, because each observation contains a full 32 byte SID. The
question is whether a full SID is required, or whether a prefix is
sufficient, or if there is some even more compact representation possible.
In principle the sender of the observation should be a direct neighbour,
and so we could just use a neighbour index. However the neighbour indices
are liable to change or become invalid over time, and we don't want to have
to trawl through the nodes every time that happens, as otherwise the CPU
requirements will be crazy.
This suggests that the use of a prefix is probably more appropriate. The
prefix must be long enough to be robust against birthday-paradox effects
and attacks. So at least 8 bytes (64 bits) is mandatory to make it
reasonably difficult to find a colliding public key prefix. Prudence
suggests that a longer prefix is desirable to give a safety margin, perhaps
12 bytes (96 bits) being a reasonable figure.
This approximately halves the memory requirement per node to about 4KB (i.e.
~250 nodes per MB), and employing shorter prefixes than 12 bytes will result
in diminishing returns, so this gives us confidence that it is an appropriate
figure.
Four-way associativity is probably reasonable for large-memory deployments
where we have space for many thousands of nodes to keep string comparison
effort to low levels.
For small-memory deployments where we have space for only a few hundred nodes it
probably makes sence to go for eight-way associativity just to be on the safe
side. However, this is somewhat arbitrary. Only experience will teach us.
One final note on potential attacks against us is that by having a hashed structure,
even with modest associativity, is that if an attacker knows the hash function
they can readily cause hash collisions and interfere with connectivity to nodes
on the mesh.
The most robust solution to this problem would be to use a linear hash function
that takes, say, 10 of the 32 bytes as input, as this would result in a hash function
space of: 32!/22! which is > 2^47. This would then require several times 2^47
observation injections by an adversary to cause a hash collision with confidence.
Actually determining that such a collision had been caused would probably multiply
the effort required by some small further constant.
Using a non-linear hash function would raise the space to 32^10 > 2^50, the factor
of 8 probably not being worth the CPU complexity of such a non-linear function.
However the question arises as to whether such an extreme approach is required,
remembering that changing the hash function does not break the protocol, so
such strong hash functions could be employed in future if needed without breaking
backward compatibility.
So let us then think about some very simple alternatives that might be good enough
for now, but that are very fast to calculate.
The simplest is to just choose a sufficient number of bytes from the SIDs to create
a sufficiently long index value. This gives 32!/(32-n)! where n is the number of
bytes required, or 32 for the worst-case situation of n.
An improvement is to xor bytes to produce the index value. Using pairs of bytes
gets us to something along the lines of 32!/(32-2n)! for production of a single byte,
which is a modest improvement, but possibly not good enough. As we increase the number
of bytes xored together the situation improves to a point. However if we go to far we
end up reducing the total space because once more than half of the bytes are involved in
the xor it is equivalent to the xor of all of the bytes xored with the bytes not included
in the xor. This means that regardless of the length of the index we need, we probably want
to use only half of the bytes as input, a this gives a complexity of 32!/16! = 2^73,
which is plenty.
In fact, this gives us a better result than the previous concept, and can be implemented
using a very simple algorithm. All we need to do is get a random ordering of the numbers
[0..31], and round robin xor the bytes we need with the [0..15]th elements of the random
ordering.
*/
/* The random ordering of bytes for the hash */
int overlay_route_hash_order[16];
int overlay_route_hash_bytes=0;
int overlay_route_initP=0;
int overlay_route_init(int mb_ram)
{
int i,j;
/* Try to catch one observed behaviour when memory corruption has occurred. */
if (overlay_route_initP) {
WHY("multiply called");
sleep(3600);
}
overlay_route_initP=1;
memabuseCheck();
srandomdev();
/* Generate hash ordering function */
strbuf b = strbuf_alloca(12 * 32);
for(i=0;i<32;i++) {
j=0;
overlay_route_hash_order[i]=random()&31;
while(j<i) {
overlay_route_hash_order[i]=random()&31;
for(j=0;j<i;j++) if (overlay_route_hash_order[i]==overlay_route_hash_order[j]) break;
}
strbuf_sprintf(b, " %d", overlay_route_hash_order[i]);
}
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("Generating byte-order for hash function:%s", strbuf_str(b));
overlay_route_hash_bytes=12;
int associativity=4;
int bin_count=1;
/* Now fiddle it to get bin_count to be a power of two that fits and doesn't waste too much space. */
long long space=(sizeof(overlay_neighbour*)*1024LL*mb_ram)+sizeof(overlay_node)*bin_count*associativity*1LL;
while (space<mb_ram*1048576LL&&associativity<8)
{
long long space2=(sizeof(overlay_neighbour*)*1024LL*mb_ram)+sizeof(overlay_node)*(bin_count*2LL)*associativity*1LL;
if (space2<mb_ram*1048576LL) { bin_count*=2; continue; }
space2=(sizeof(overlay_neighbour*)*1024LL)+sizeof(overlay_node)*bin_count*(associativity+1)*1LL;
if (space2<mb_ram*1048576LL) { associativity++; continue; }
break;
}
/* Report on the space used */
{
space=(sizeof(overlay_neighbour*)*1024LL*mb_ram)+sizeof(overlay_node)*bin_count*associativity*1LL;
int percent=100LL*space/(mb_ram*1048576LL);
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("Using %d%% of %dMB RAM allows for %d bins with %d-way associativity and %d direct neighbours",
percent,mb_ram,bin_count,associativity,1024*mb_ram);
}
/* Now allocate the structures */
overlay_nodes=calloc(sizeof(overlay_node*),bin_count);
if (!overlay_nodes) return WHY_perror("calloc");
overlay_neighbours=calloc(sizeof(overlay_neighbour),1024*mb_ram);
if (!overlay_neighbours) {
WHY_perror("calloc");
free(overlay_nodes);
return -1;
}
for(i=0;i<bin_count;i++)
{
overlay_nodes[i]=calloc(sizeof(overlay_node),associativity);
if (!overlay_nodes[i]) {
WHY_perror("calloc");
while(--i>=0) free(overlay_nodes[i]);
free(overlay_nodes);
free(overlay_neighbours);
return -1;
}
}
overlay_max_neighbours=1024*mb_ram;
overlay_bin_count=bin_count;
overlay_bin_size=associativity;
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("Node (%d bins) and neighbour tables allocated",bin_count);
/* Work out number of bytes required to represent the bin number.
Used for calculation of sid hash */
overlay_bin_bytes=1;
while(bin_count&0xffffff00) {
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("bin_count=0x%08x, overlay_bin_bytes=%d",bin_count,overlay_bin_bytes);
overlay_bin_bytes++;
bin_count=bin_count>>8;
}
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("bin_count=0x%08x, overlay_bin_bytes=%d",bin_count,overlay_bin_bytes);
return 0;
}
/* Select a next hop to get to a node.
Frist, let us consider neighbours. These are on a local link to us, and do not require any
@ -387,8 +210,6 @@ int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *interface)
return 0;
}
if (!overlay_neighbours) return WHY("I have no neighbours");
overlay_node *n=overlay_route_find_node(d,SID_SIZE,0 /* don't create if missing */ );
if (!n){
if (debug&DEBUG_OVERLAYROUTING)
@ -397,7 +218,7 @@ int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *interface)
}
time_ms_t now = gettime_ms();
overlay_neighbour *direct_neighbour=NULL;
struct overlay_neighbour *direct_neighbour=NULL;
if (n->neighbour_id) {
direct_neighbour = &overlay_neighbours[n->neighbour_id];
@ -432,9 +253,9 @@ int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *interface)
if (!score)
continue;
overlay_neighbour *neighbour
struct overlay_neighbour *neighbour
=overlay_route_get_neighbour_structure
(n->observations[o].sender_prefix,OVERLAY_SENDER_PREFIX_LENGTH,0);
(n->observations[o].sender->node,0);
if (neighbour && neighbour!=direct_neighbour) {
overlay_route_recalc_neighbour_metrics(neighbour, now);
@ -442,7 +263,7 @@ int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *interface)
for(i=1;i<OVERLAY_MAX_INTERFACES;i++) {
if (overlay_interfaces[i].state==INTERFACE_STATE_UP &&
neighbour->scores[i]*score>best_score) {
bcopy(&neighbour->node->sid[0],&nexthop[0],SID_SIZE);
bcopy(neighbour->node->subscriber->sid,nexthop,SID_SIZE);
*interface=i;
best_o=o;
best_score=score;
@ -459,91 +280,33 @@ int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *interface)
}
}
unsigned int overlay_route_hash_sid(const unsigned char *sid)
{
/* Calculate the bin number of an address (sid) from the sid. */
if (!overlay_route_hash_bytes) return WHY("overlay_route_hash_bytes==0");
unsigned int bin=0;
int byte=0;
int i;
for(i=0;i<overlay_route_hash_bytes;i++) {
bin=bin^((sid[overlay_route_hash_order[i]])<<(8*byte));
byte++;
if (byte>=overlay_bin_bytes) byte=0;
}
/* Mask out extranous bits to return only a valid bin number */
bin&=(overlay_bin_count-1);
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("Address %s resolves to bin #%d", alloca_tohex_sid(sid), bin);
return bin;
}
overlay_node *overlay_route_find_node(const unsigned char *sid, int prefixLen, int createP)
{
if (*sid==0 || prefixLen<overlay_route_hash_bytes){
if (*sid==0){
INFOF("Sid %s/%d cannot ever become a node!", alloca_tohex_sid(sid), prefixLen);
return NULL;
}
int bin_number = overlay_route_hash_sid(sid);
if (bin_number < 0) {
WHY("negative bin number");
struct subscriber *subscriber = find_subscriber(sid, prefixLen, createP);
if (!subscriber)
return NULL;
}
int free_slot = -1;
overlay_node *found=NULL;
{
int slot;
for (slot = 0; slot < overlay_bin_size; slot++)
if (overlay_nodes[bin_number][slot].sid[0]==0)
free_slot = slot;
else if (memcmp(sid, overlay_nodes[bin_number][slot].sid, prefixLen) == 0){
if (found){
INFOF("SID prefix %d %s is not unique", prefixLen, alloca_tohex_sid(sid));
return NULL;
}
found = &overlay_nodes[bin_number][slot];
}
}
if (found)
return found;
/* Didn't find it */
if (!createP) return NULL;
if (free_slot == -1) {
/* Evict */
WARN("overlay_nodes[] eviction NOT IMPLEMENTED");
return NULL;
int i;
for(i=0;i<OVERLAY_MAX_OBSERVATIONS;i++)
overlay_nodes[bin_number][free_slot].observations[i].observed_score=0;
overlay_nodes[bin_number][free_slot].neighbour_id=0;
overlay_nodes[bin_number][free_slot].most_recent_observation_id=0;
overlay_nodes[bin_number][free_slot].best_link_score=0;
overlay_nodes[bin_number][free_slot].best_observation=0;
for(i=0;i<OVERLAY_MAX_INTERFACES;i++) {
overlay_nodes[bin_number][free_slot].most_recent_advertisment_ms[i]=0;
overlay_nodes[bin_number][free_slot].most_recent_advertised_score[i]=0;
}
}
bcopy(sid, overlay_nodes[bin_number][free_slot].sid, SID_SIZE);
if ((!subscriber->node) && createP){
subscriber->node = (overlay_node *)malloc(sizeof(overlay_node));
memset(subscriber->node,0,sizeof(overlay_node));
subscriber->node->subscriber = subscriber;
// This info message is used by tests; don't alter or remove it.
INFOF("ADD OVERLAY NODE sid=%s slot=%d", alloca_tohex_sid(sid), free_slot);
INFOF("ADD OVERLAY NODE sid=%s", alloca_tohex_sid(sid));
}
return &overlay_nodes[bin_number][free_slot];
return subscriber->node;
}
int overlay_route_ack_selfannounce(overlay_frame *f,
unsigned int s1,unsigned int s2,
int interface,
overlay_neighbour *n)
struct overlay_neighbour *n)
{
/* Acknowledge the receipt of a self-announcement of an immediate neighbour.
We could acknowledge immediately, but that requires the transmission of an
@ -580,10 +343,7 @@ int overlay_route_ack_selfannounce(overlay_frame *f,
XXX 6 is quite an arbitrary selection however. */
/* Set destination of ack to source of observed frame */
if (overlay_frame_set_neighbour_as_destination(out,n)) {
op_free(out);
return WHY("overlay_frame_set_neighbour_as_source() failed");
}
bcopy(n->node->subscriber->sid, out->destination, SID_SIZE);
/* set source to ourselves */
overlay_frame_set_me_as_source(out);
@ -678,7 +438,7 @@ int overlay_route_make_neighbour(overlay_node *n)
if (n->neighbour_id) return 0;
/* If address is local don't both making it a neighbour */
if (overlay_address_is_local(n->sid)) return 0;
if (overlay_address_is_local(n->subscriber->sid)) return 0;
/* It isn't yet a neighbour, so find or free a neighbour slot */
/* slot 0 is reserved, so skip it */
@ -692,40 +452,28 @@ int overlay_route_make_neighbour(overlay_node *n)
if (overlay_neighbours[nid].node) overlay_neighbours[nid].node->neighbour_id=0;
n->neighbour_id=nid;
}
bzero(&overlay_neighbours[n->neighbour_id],sizeof(overlay_neighbour));
bzero(&overlay_neighbours[n->neighbour_id],sizeof(struct overlay_neighbour));
overlay_neighbours[n->neighbour_id].node=n;
return 0;
}
overlay_neighbour *overlay_route_get_neighbour_structure(unsigned char *packed_sid,
int prefixLen,int createP)
struct overlay_neighbour *overlay_route_get_neighbour_structure(overlay_node *node, int createP)
{
IN();
if (overlay_address_is_local(packed_sid)) {
WHY("asked for neighbour structure for myself");
RETURN(NULL);
}
overlay_node *n=overlay_route_find_node(packed_sid,prefixLen,createP);
if (!n) {
// WHY("Could not find node record for observed node");
RETURN(NULL);
}
if (!node)
return NULL;
/* Check if node is already a neighbour, or if not, make it one */
if (!n->neighbour_id){
if (!node->neighbour_id){
if (!createP)
RETURN(NULL);
return NULL;
if (overlay_route_make_neighbour(n)) {
WHY("overlay_route_make_neighbour() failed");
RETURN(NULL);
}
if (overlay_route_make_neighbour(node))
return WHYNULL("overlay_route_make_neighbour() failed");
}
/* Get neighbour structure */
RETURN(&overlay_neighbours[n->neighbour_id]);
return &overlay_neighbours[node->neighbour_id];
}
int overlay_route_i_can_hear_node(unsigned char *who,int sender_interface,
@ -747,7 +495,8 @@ int overlay_route_node_can_hear_me(unsigned char *who,int sender_interface,
3. Update score of how reliably we can hear this node */
/* Get neighbour structure */
overlay_neighbour *neh=overlay_route_get_neighbour_structure(who,SID_SIZE,1 /* create if necessary */);
struct subscriber *subscriber = find_subscriber(who, SID_SIZE, 1);
struct overlay_neighbour *neh=overlay_route_get_neighbour_structure(subscriber->node,1 /* create if necessary */);
if (!neh)
return -1;
@ -801,17 +550,17 @@ int overlay_route_saw_selfannounce(overlay_frame *f, time_ms_t now)
IN();
unsigned int s1,s2;
unsigned char sender_interface;
overlay_neighbour *n=overlay_route_get_neighbour_structure(f->source,SID_SIZE,
1 /* make neighbour if not yet one */);
overlay_node *node = overlay_route_find_node(f->source, SID_SIZE, 1);
if (!node)
RETURN(-1);
struct overlay_neighbour *n=overlay_route_get_neighbour_structure(node, 1 /* make neighbour if not yet one */);
if (!n){
RETURN(-1);
}
/* Record current sender for reference by addresses in subsequent frames in the
ensemble */
overlay_abbreviate_set_current_sender(f->source);
s1=ob_get_int(f->payload, 0);
s2=ob_get_int(f->payload, 4);
sender_interface=ob_getbyte(f->payload, 8);
@ -832,9 +581,6 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
int best_score=0;
int best_observation=-1;
if (n->sid[0]==0)
return 0;
for(o=0;o<OVERLAY_MAX_OBSERVATIONS;o++)
{
if (n->observations[o].observed_score)
@ -855,13 +601,16 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
/* Node is also a direct neighbour, so check score that way */
if (n->neighbour_id>overlay_max_neighbours||n->neighbour_id<0)
return WHY("n->neighbour_id is invalid.");
struct overlay_neighbour *neighbour=&overlay_neighbours[n->neighbour_id];
int i;
for(i=0;i<overlay_interface_count;i++)
{
if (overlay_interfaces[i].state==INTERFACE_STATE_UP &&
overlay_neighbours[n->neighbour_id].scores[i]>best_score)
neighbour->scores[i]>best_score)
{
best_score=overlay_neighbours[n->neighbour_id].scores[i];
best_score=neighbour->scores[i];
best_observation=-1;
}
}
@ -879,16 +628,16 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
}
if (n->best_link_score && !best_score){
INFOF("PEER UNREACHABLE, sid=%s", alloca_tohex_sid(n->sid));
monitor_announce_unreachable_peer(n->sid);
INFOF("PEER UNREACHABLE, sid=%s", alloca_tohex_sid(n->subscriber->sid));
monitor_announce_unreachable_peer(n->subscriber->sid);
}else if(best_score && !n->best_link_score){
INFOF("PEER REACHABLE, sid=%s", alloca_tohex_sid(n->sid));
INFOF("PEER REACHABLE, sid=%s", alloca_tohex_sid(n->subscriber->sid));
/* Make sure node is advertised soon */
overlay_route_please_advertise(n);
monitor_announce_peer(n->sid);
monitor_announce_peer(n->subscriber->sid);
/* Pre-emptively check if we have their sas in memory, or send a request */
keyring_find_sas_public(keyring, n->sid);
keyring_find_sas_public(keyring, n->subscriber->sid);
}
/* Remember new reachability information */
@ -917,16 +666,17 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
200 seconds perhaps?). Also, if no recent observations, then we further
limit the score.
*/
int overlay_route_recalc_neighbour_metrics(overlay_neighbour *n, time_ms_t now)
int overlay_route_recalc_neighbour_metrics(struct overlay_neighbour *n, time_ms_t now)
{
int i;
time_ms_t most_recent_observation=0;
IN();
if (!n->node)
return 0;
RETURN(0);
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("Updating neighbour metrics for %s", alloca_tohex_sid(n->node->sid));
DEBUGF("Updating neighbour metrics for %s", alloca_tohex_sid(n->node->subscriber->sid));
/* At most one update per half second */
if (n->last_metric_update == 0) {
@ -937,7 +687,7 @@ int overlay_route_recalc_neighbour_metrics(overlay_neighbour *n, time_ms_t now)
if (ago < 500) {
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("last update was %lldms ago -- skipping", (long long)ago);
return 0;
RETURN (0);
}
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("last update was %lldms ago", (long long)ago);
@ -1034,8 +784,7 @@ int overlay_route_recalc_neighbour_metrics(overlay_neighbour *n, time_ms_t now)
if (scoreChanged)
overlay_route_recalc_node_metrics(n->node, now);
return 0;
RETURN(0);
}
/*
@ -1061,17 +810,12 @@ int overlay_route_recalc_neighbour_metrics(overlay_neighbour *n, time_ms_t now)
*/
int overlay_route_saw_selfannounce_ack(overlay_frame *f,long long now)
{
IN();
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("processing selfannounce ack (payload length=%d)",f->payload->length);
if (!overlay_neighbours) {
if (debug&DEBUG_OVERLAYROUTING)
DEBUG("no neighbours, so returning immediately");
return 0;
}
if (f->payload->length<9)
return WHY("FOO! selfannounce ack packet too short");
RETURN(WHY("FOO! selfannounce ack packet too short"));
unsigned int s1=ob_get_int(f->payload,0);
unsigned int s2=ob_get_int(f->payload,4);
@ -1080,7 +824,7 @@ int overlay_route_saw_selfannounce_ack(overlay_frame *f,long long now)
// Call something like the following for each link
overlay_route_node_can_hear_me(f->source,iface,s1,s2,now);
return 0;
RETURN(0);
}
/* if to and via are the same, then this is evidence that we can get to the
@ -1090,6 +834,7 @@ int overlay_route_record_link(time_ms_t now, unsigned char *to,
unsigned int s1,unsigned int s2,int score,
int gateways_en_route)
{
IN();
if (debug & DEBUG_OVERLAYROUTING)
DEBUGF("to=%s, via=%s, sender_interface=%d, s1=%d, s2=%d score=%d gateways_en_route=%d",
alloca_tohex_sid(to), alloca_tohex_sid(via), sender_interface, s1, s2,
@ -1099,12 +844,17 @@ int overlay_route_record_link(time_ms_t now, unsigned char *to,
if (sender_interface>OVERLAY_MAX_INTERFACES || score == 0) {
if (debug & DEBUG_OVERLAYROUTING)
DEBUG("invalid report");
return 0;
RETURN(0);
}
overlay_node *n = overlay_route_find_node(to, SID_SIZE, 1 /* create node if missing */);
if (!n)
return WHY("Could not create entry for node");
RETURN(WHY("Could not create entry for node"));
struct subscriber *sender = find_subscriber(via, SID_SIZE, 1);
if (!sender)
RETURN(WHY("Could not create subscriber"));
int slot = -1;
int i;
for (i = 0; i < OVERLAY_MAX_OBSERVATIONS; ++i) {
@ -1113,7 +863,7 @@ int overlay_route_record_link(time_ms_t now, unsigned char *to,
slot = i;
/* If the intermediate host ("via") address and interface numbers match, then overwrite old
observation with new one */
if (memcmp(via, n->observations[i].sender_prefix, OVERLAY_SENDER_PREFIX_LENGTH) == 0) {
if (n->observations[i].sender == sender) {
slot = i;
break;
}
@ -1127,9 +877,9 @@ int overlay_route_record_link(time_ms_t now, unsigned char *to,
DEBUGF("allocate observation slot=%d", slot);
} else {
if (debug & DEBUG_OVERLAYROUTING)
DEBUGF("overwrite observation slot=%d (sender_prefix=%s interface=%u observed_score=%u rx_time=%lld)",
DEBUGF("overwrite observation slot=%d (sender=%s interface=%u observed_score=%u rx_time=%lld)",
slot,
alloca_tohex(n->observations[slot].sender_prefix, OVERLAY_SENDER_PREFIX_LENGTH),
n->observations[slot].sender?alloca_tohex_sid(n->observations[slot].sender->sid):"[None]",
n->observations[slot].interface,
n->observations[slot].observed_score,
n->observations[slot].rx_time
@ -1139,7 +889,7 @@ int overlay_route_record_link(time_ms_t now, unsigned char *to,
n->observations[slot].observed_score=0;
n->observations[slot].gateways_en_route=gateways_en_route;
n->observations[slot].rx_time=now;
bcopy(via,n->observations[slot].sender_prefix,OVERLAY_SENDER_PREFIX_LENGTH);
n->observations[slot].sender = sender;
n->observations[slot].observed_score=score;
n->observations[slot].interface=sender_interface;
@ -1161,7 +911,7 @@ int overlay_route_record_link(time_ms_t now, unsigned char *to,
if (debug & DEBUG_OVERLAYROUTEMONITOR)
overlay_route_dump();
return 0;
RETURN(0);
}
int overlay_address_is_local(unsigned char *s)
@ -1172,9 +922,34 @@ int overlay_address_is_local(unsigned char *s)
return found;
}
int node_dump(struct subscriber *subscriber, void *context){
strbuf *b=context;
overlay_node *node = subscriber->node;
int o;
if (node){
strbuf_sprintf(*b," %s* : %d :", alloca_tohex(subscriber->sid, 7),
node->best_link_score);
for(o=0;o<OVERLAY_MAX_OBSERVATIONS;o++)
{
if (node->observations[o].observed_score)
{
overlay_node_observation *ob=&node->observations[o];
if (ob->corrected_score)
strbuf_sprintf(*b," %d/%d via %s*",
ob->corrected_score,ob->gateways_en_route,
alloca_tohex(ob->sender->sid,7));
}
}
strbuf_sprintf(*b,"\n");
}
return 0;
}
int overlay_route_dump()
{
int bin,slot,o,n,i;
int n,i;
time_ms_t now = gettime_ms();
strbuf b = strbuf_alloca(8192);
@ -1199,7 +974,7 @@ int overlay_route_dump()
if (overlay_neighbours[n].node)
{
strbuf_sprintf(b," %s* : %lldms ago :",
alloca_tohex(overlay_neighbours[n].node->sid, 7),
alloca_tohex(overlay_neighbours[n].node->subscriber->sid, 7),
(long long)(now - overlay_neighbours[n].last_observation_time_ms));
for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
if (overlay_neighbours[n].scores[i])
@ -1211,26 +986,9 @@ int overlay_route_dump()
strbuf_reset(b);
strbuf_sprintf(b,"Overlay Mesh Route Table\n------------------------\n");
for(bin=0;bin<overlay_bin_count;bin++)
for(slot=0;slot<overlay_bin_size;slot++)
{
if (!overlay_nodes[bin][slot].sid[0]) continue;
strbuf_sprintf(b," %s* : %d :", alloca_tohex(overlay_nodes[bin][slot].sid, 7),
overlay_nodes[bin][slot].best_link_score);
for(o=0;o<OVERLAY_MAX_OBSERVATIONS;o++)
{
if (overlay_nodes[bin][slot].observations[o].observed_score)
{
overlay_node_observation *ob=&overlay_nodes[bin][slot].observations[o];
if (ob->corrected_score)
strbuf_sprintf(b," %d/%d via %s*",
ob->corrected_score,ob->gateways_en_route,
alloca_tohex(ob->sender_prefix, 7));
}
}
strbuf_sprintf(b,"\n");
}
enum_subscribers(NULL, node_dump, &b);
DEBUG(strbuf_str(b));
return 0;
}
@ -1240,94 +998,6 @@ int max(int a,int b)
if (a>b) return a; else return b;
}
/*
We want to progressivelly update all routes as we go along, updating a few nodes
every call, so that no one call takes too long. This is important since we don't
want to add any excessive delays that might upset delay-sensitive voice and video
traffic.
*/
int overlay_route_tick_next_neighbour_id=0;
int overlay_route_tick_neighbour_bundle_size=1;
int overlay_route_tick_next_node_bin_id=0;
int overlay_route_tick_node_bundle_size=1;
void overlay_route_tick(struct sched_ent *alarm)
{
int n;
time_ms_t start_time = gettime_ms();
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("Neighbours: %d@%d, Nodes: %d@%d",
overlay_route_tick_neighbour_bundle_size,overlay_route_tick_next_neighbour_id,
overlay_route_tick_node_bundle_size,overlay_route_tick_next_node_bin_id);
/* Go through some of neighbour list */
// TODO This doesn't seem to be reliable
// note that neighbour metrics are now re-calculated in overlay_get_nexthop when we need them
n=overlay_route_tick_neighbour_bundle_size;
if (n<1) n=1;
while(n--)
{
overlay_route_tick_neighbour(overlay_route_tick_next_neighbour_id++,start_time);
if (overlay_route_tick_next_neighbour_id>=overlay_neighbour_count) overlay_route_tick_next_neighbour_id=0;
}
/* Tweak neighbour bundle size to spread it out over the required time.
XXX Does this behave correctly when there are no neighbours? */
time_ms_t neighbour_time = gettime_ms() - start_time;
if (neighbour_time>2) overlay_route_tick_neighbour_bundle_size/=neighbour_time;
else if (neighbour_time==0) overlay_route_tick_neighbour_bundle_size*=2;
if (overlay_route_tick_neighbour_bundle_size<1) overlay_route_tick_neighbour_bundle_size=1;
if (overlay_route_tick_neighbour_bundle_size>overlay_neighbour_count)
overlay_route_tick_neighbour_bundle_size=overlay_neighbour_count;
/* Go through some of node list */
n=overlay_route_tick_node_bundle_size;
if (n<1) n=1;
while(n--)
{
int slot;
for(slot=0;slot<overlay_bin_size;slot++) {
overlay_route_tick_node(overlay_route_tick_next_node_bin_id,slot,start_time);
}
overlay_route_tick_next_node_bin_id++;
if (overlay_route_tick_next_node_bin_id>=overlay_bin_count) overlay_route_tick_next_node_bin_id=0;
}
/* Tweak neighbour bundle size to spread it out over the required time.
Allow 2ms here instead of 1ms, as neighbour processing may have taken the
bulk of the tick. */
time_ms_t node_time = gettime_ms() - neighbour_time - start_time;
if (node_time>1) overlay_route_tick_node_bundle_size/=node_time;
else if (node_time==0) overlay_route_tick_node_bundle_size*=2;
if (overlay_route_tick_node_bundle_size<1) overlay_route_tick_node_bundle_size=1;
/* Limit bundle sizes to sanity */
if (overlay_route_tick_neighbour_bundle_size>overlay_neighbour_count
&&overlay_neighbour_count)
overlay_route_tick_neighbour_bundle_size=overlay_neighbour_count;
if (overlay_route_tick_node_bundle_size>overlay_bin_count)
overlay_route_tick_node_bundle_size=overlay_bin_count;
/* Work out how long to have between route ticks to make sure we update all route scores
every 5 seconds. */
int ticks=max(overlay_neighbour_count
?overlay_neighbour_count/overlay_route_tick_neighbour_bundle_size:0,
overlay_bin_count/overlay_route_tick_node_bundle_size);
if (ticks<1) ticks=1;
if (ticks>5000) ticks=5000;
int interval=5000/ticks;
if (debug&DEBUG_OVERLAYROUTING) DEBUGF("route tick interval = %dms (%d ticks per 5sec, neigh=%lldms, node=%lldms)",interval,ticks,neighbour_time,node_time);
/* Update callback interval based on how much work we have to do */
alarm->alarm = gettime_ms()+interval;
alarm->deadline = alarm->alarm+100;
schedule(alarm);
return;
}
/* Ticking neighbours is easy; we just pretend we have heard from them again,
and recalculate the score that way, which already includes a mechanism for
taking into account the age of the most recent observation */
@ -1350,15 +1020,35 @@ int overlay_route_tick_neighbour(int neighbour_id, time_ms_t now)
most part we can tolerate these without any special action, as their high
scores will keep them reachable for longer anyway.
*/
int overlay_route_tick_node(int bin,int slot, time_ms_t now)
int overlay_route_tick_node(struct subscriber *subscriber, void *context)
{
return overlay_route_recalc_node_metrics(&overlay_nodes[bin][slot],now);
if (subscriber->node)
overlay_route_recalc_node_metrics(subscriber->node, gettime_ms());
return 0;
}
void overlay_route_tick(struct sched_ent *alarm)
{
int n;
time_ms_t now = gettime_ms();
/* Go through some of neighbour list */
for (n=0;n<overlay_max_neighbours;n++)
overlay_route_tick_neighbour(n,now);
/* Go through the node list */
enum_subscribers(NULL, overlay_route_tick_node, NULL);
/* Update callback interval based on how much work we have to do */
alarm->alarm = gettime_ms()+5000;
alarm->deadline = alarm->alarm+100;
schedule(alarm);
return;
}
int overlay_route_node_info(overlay_mdp_frame *mdp,
struct sockaddr_un *addr,int addrlen)
{
int bin,slot,n;
time_ms_t now = gettime_ms();
if (0)
@ -1381,8 +1071,6 @@ int overlay_route_node_info(overlay_mdp_frame *mdp,
&keyring->contexts[cn]->identities[in]
->keypairs[kp]->public_key[0],
mdp->nodeinfo.sid_prefix_length/2))
{
if (mdp->nodeinfo.count==mdp->nodeinfo.index)
{
mdp->nodeinfo.foundP=1;
mdp->nodeinfo.localP=1;
@ -1418,28 +1106,27 @@ int overlay_route_node_info(overlay_mdp_frame *mdp,
mdp->nodeinfo.resolve_did=1;
}
}
}
mdp->nodeinfo.count++;
return overlay_mdp_reply(mdp_named.poll.fd,addr,addrlen,mdp);
}
}
/* check neighbour table, i.e., if directly connected */
for(n=0;n<overlay_neighbour_count;n++)
if (overlay_neighbours[n].node)
{
if (!memcmp(&mdp->nodeinfo.sid[0],
&overlay_neighbours[n].node->sid[0],
mdp->nodeinfo.sid_prefix_length/2))
{
if (mdp->nodeinfo.count==mdp->nodeinfo.index)
{
struct subscriber *subscriber = find_subscriber(mdp->nodeinfo.sid, mdp->nodeinfo.sid_prefix_length/2, 0);
if (subscriber && subscriber->node){
overlay_node *node = subscriber->node;
mdp->nodeinfo.foundP=1;
mdp->nodeinfo.localP=0;
mdp->nodeinfo.neighbourP=1;
mdp->nodeinfo.time_since_last_observation = gettime_ms() - overlay_neighbours[n].last_observation_time_ms;
mdp->nodeinfo.score=-1;
mdp->nodeinfo.interface_number=-1;
mdp->nodeinfo.resolve_did=0;
bcopy(subscriber->sid,
mdp->nodeinfo.sid,SID_SIZE);
if (subscriber->node->neighbour_id){
int n = subscriber->node->neighbour_id;
mdp->nodeinfo.neighbourP=1;
mdp->nodeinfo.time_since_last_observation = now - overlay_neighbours[n].last_observation_time_ms;
int i;
for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
if (overlay_neighbours[n].scores[i]>mdp->nodeinfo.score)
@ -1448,49 +1135,21 @@ int overlay_route_node_info(overlay_mdp_frame *mdp,
mdp->nodeinfo.interface_number=i;
}
bcopy(&overlay_neighbours[n].node->sid[0],
&mdp->nodeinfo.sid[0],SID_SIZE);
}
mdp->nodeinfo.count++;
}
}
/* check if it is an indirectly connected node that we know about */
for(bin=0;bin<overlay_bin_count;bin++)
for(slot=0;slot<overlay_bin_size;slot++)
{
if (!overlay_nodes[bin][slot].sid[0]) continue;
if (!memcmp(&mdp->nodeinfo.sid[0],
&overlay_nodes[bin][slot].sid[0],
mdp->nodeinfo.sid_prefix_length/2))
{
if (mdp->nodeinfo.count==mdp->nodeinfo.index)
{
mdp->nodeinfo.foundP=1;
mdp->nodeinfo.localP=0;
}else{
mdp->nodeinfo.neighbourP=0;
mdp->nodeinfo.time_since_last_observation = gettime_ms();
mdp->nodeinfo.score=-1;
mdp->nodeinfo.interface_number=-1;
mdp->nodeinfo.resolve_did=0;
mdp->nodeinfo.time_since_last_observation = -1;
int o;
for(o=0;o<OVERLAY_MAX_OBSERVATIONS;o++)
if (overlay_nodes[bin][slot].observations[o].observed_score)
if (node->observations[o].observed_score)
{
overlay_node_observation *ob
=&overlay_nodes[bin][slot].observations[o];
=&node->observations[o];
if (ob->corrected_score>mdp->nodeinfo.score) {
mdp->nodeinfo.score=ob->corrected_score;
}
if (now - ob->rx_time < mdp->nodeinfo.time_since_last_observation)
if (mdp->nodeinfo.time_since_last_observation == -1 || now - ob->rx_time < mdp->nodeinfo.time_since_last_observation)
mdp->nodeinfo.time_since_last_observation = now - ob->rx_time;
}
bcopy(&overlay_nodes[bin][slot].sid[0],
&mdp->nodeinfo.sid[0],SID_SIZE);
}
mdp->nodeinfo.count++;
}
}

View File

@ -689,21 +689,6 @@ int rfs_length(int l);
int rfs_encode(int l,unsigned char *b);
int rfs_decode(unsigned char *b,int *offset);
typedef struct overlay_neighbour_observation {
/* Sequence numbers are handled as ranges because the tick
rate can vary between interfaces, and we want to be able to
estimate the reliability of links to nodes that may have
several available interfaces.
We don't want sequence numbers to wrap too often, but we
would also like to support fairly fast ticking interfaces,
e.g., for gigabit type links. So lets go with 1ms granularity. */
unsigned int s1;
unsigned int s2;
time_ms_t time_ms;
unsigned char sender_interface;
unsigned char valid;
} overlay_neighbour_observation;
typedef struct overlay_node_observation {
unsigned char observed_score; /* serves as validty check also */
unsigned char corrected_score;
@ -711,12 +696,12 @@ typedef struct overlay_node_observation {
unsigned char RESERVED; /* for alignment */
unsigned char interface;
time_ms_t rx_time;
unsigned char sender_prefix[OVERLAY_SENDER_PREFIX_LENGTH];
struct subscriber *sender;
} overlay_node_observation;
typedef struct overlay_node {
unsigned char sid[SID_SIZE];
struct subscriber *subscriber;
int neighbour_id; /* 0=not a neighbour */
int most_recent_observation_id;
int best_link_score;
@ -730,37 +715,13 @@ typedef struct overlay_node {
overlay_node_observation observations[OVERLAY_MAX_OBSERVATIONS];
} overlay_node;
typedef struct overlay_neighbour {
time_ms_t last_observation_time_ms;
time_ms_t last_metric_update;
int most_recent_observation_id;
overlay_neighbour_observation observations[OVERLAY_MAX_OBSERVATIONS];
overlay_node *node;
/* Scores of visibility from each of the neighbours interfaces.
This is so that the sender knows which interface to use to reach us.
*/
unsigned char scores[OVERLAY_MAX_INTERFACES];
/* One-byte index entries for address abbreviation */
unsigned char one_byte_index_address_prefixes[256][OVERLAY_SENDER_PREFIX_LENGTH];
} overlay_neighbour;
extern overlay_neighbour *overlay_neighbours;
int overlay_route_init(int mb_ram);
int overlay_route_saw_selfannounce_ack(overlay_frame *f, time_ms_t now);
int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now);
int overlay_route_recalc_neighbour_metrics(overlay_neighbour *n, time_ms_t now);
int overlay_route_saw_selfannounce(overlay_frame *f, time_ms_t now);
overlay_node *overlay_route_find_node(const unsigned char *sid,int prefixLen,int createP);
unsigned int overlay_route_hash_sid(const unsigned char *sid);
int overlay_route_init(int mb_ram);
overlay_neighbour *overlay_route_get_neighbour_structure(unsigned char *packed_sid,
int prefixLen,int createP);
unsigned char *overlay_get_my_sid();
int overlay_frame_set_me_as_source(overlay_frame *f);
int overlay_frame_set_neighbour_as_source(overlay_frame *f,overlay_neighbour *n);
int overlay_frame_set_neighbour_as_destination(overlay_frame *f,overlay_neighbour *n);
int overlay_frame_set_broadcast_as_destination(overlay_frame *f);
int overlay_broadcast_generate_address(unsigned char *a);
int packetEncipher(unsigned char *packet,int maxlen,int *len,int cryptoflags);
@ -771,17 +732,10 @@ int overlay_route_record_link( time_ms_t now,unsigned char *to,
unsigned char *via,int sender_interface,
unsigned int s1,unsigned int s2,int score,int gateways_en_route);
int overlay_route_dump();
int overlay_route_tick_neighbour(int neighbour_id, time_ms_t now);
int overlay_route_tick_node(int bin,int slot, time_ms_t now);
int overlay_route_add_advertisements(overlay_buffer *e);
int ovleray_route_please_advertise(overlay_node *n);
int overlay_abbreviate_set_current_sender(unsigned char *in);
extern int overlay_bin_count;
extern int overlay_bin_size; /* associativity, i.e., entries per bin */
extern int overlay_bin_bytes;
extern overlay_node **overlay_nodes;
int overlay_route_saw_advertisements(int i,overlay_frame *f, time_ms_t now);
int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, time_ms_t now);
int overlay_route_please_advertise(overlay_node *n);
@ -916,7 +870,7 @@ typedef struct overlay_mdp_vompevent {
typedef struct overlay_mdp_nodeinfo {
unsigned char sid[SID_SIZE];
int sid_prefix_length; /* allow wildcard matching */
int sid_prefix_length; /* must be long enough to be unique */
char did[64];
char name[64];
int foundP;
@ -926,8 +880,6 @@ typedef struct overlay_mdp_nodeinfo {
int interface_number;
int resolve_did;
time_ms_t time_since_last_observation;
int index; /* which record to return or was returned (incase there are multiple matches) */
int count; /* number of matching records */
} overlay_mdp_nodeinfo;
typedef struct overlay_mdp_frame {

View File

@ -43,7 +43,7 @@ unsigned char get_nibble(const unsigned char *sid, int pos){
// find a subscriber struct from a subscriber id
// TODO find abreviated sid's
struct subscriber *find(const unsigned char *sid, int len, int create){
struct subscriber *find_subscriber(const unsigned char *sid, int len, int create){
struct tree_node *ptr = &root;
int pos=0;
if (len!=SID_SIZE)
@ -60,6 +60,7 @@ struct subscriber *find(const unsigned char *sid, int len, int create){
if (create){
struct subscriber *ret=(struct subscriber *)malloc(sizeof(struct subscriber));
memset(ret,0,sizeof(struct subscriber));
ptr->subscribers[nibble]=ret;
bcopy(sid, ret->sid, SID_SIZE);
ret->abbreviate_len=pos;
@ -95,18 +96,34 @@ struct subscriber *find(const unsigned char *sid, int len, int create){
return NULL;
}
void dump_subscriber_tree(struct tree_node *node, int depth){
int i;
for (i=0;i<16;i++){
/*
Walk the subscriber tree, calling the callback function for each subscriber.
if start is a valid pointer, the first entry returned will be after this subscriber
if the callback returns non-zero, the process will stop.
*/
int walk_tree(struct tree_node *node, int pos, struct subscriber *start,
int(*callback)(struct subscriber *, void *), void *context){
int i=0;
if (start){
i=get_nibble(start->sid,pos);
}
for (;i<16;i++){
if (node->is_tree & (1<<i)){
DEBUGF("%d, %x",depth,i);
dump_subscriber_tree(node->tree_nodes[i],depth+1);
}else if(node->subscribers[i]){
DEBUGF("%d, %x, %s", node->subscribers[i]->abbreviate_len, i, alloca_tohex_sid(node->subscribers[i]->sid));
if (walk_tree(node->tree_nodes[i], pos+1, start, callback, context))
return 1;
}else if(node->subscribers[i] && node->subscribers[i] != start){
if (callback(node->subscribers[i], context))
return 1;
}
}
return 0;
}
void dump_subscribers(){
dump_subscriber_tree(&root,0);
/*
walk the tree, starting at start, calling the callback function
*/
void enum_subscribers(struct subscriber *start, int(*callback)(struct subscriber *, void *), void *context){
walk_tree(&root, 0, start, callback, context);
}

View File

@ -14,10 +14,11 @@ struct subscriber{
unsigned char sid[SID_SIZE];
// minimum abbreviation length, in 4bit nibbles.
int abbreviate_len;
overlay_node *node;
};
struct subscriber *find(const unsigned char *sid, int len, int create);
void dump_subscribers();
struct subscriber *find_subscriber(const unsigned char *sid, int len, int create);
void enum_subscribers(struct subscriber *start, int(*callback)(struct subscriber *, void *), void *context);
#endif