mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-21 06:03:12 +00:00
Refactor routing node information to use new subscriber tree
This commit is contained in:
parent
30d5ed2b6d
commit
aa5706f9d7
@ -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");
|
||||
|
@ -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.
|
||||
|
20
monitor.c
20
monitor.c
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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);
|
||||
|
683
overlay_route.c
683
overlay_route.c
@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
56
serval.h
56
serval.h
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user