diff --git a/commandline.c b/commandline.c index 8c69c790..5cf761c4 100644 --- a/commandline.c +++ b/commandline.c @@ -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"); diff --git a/constants.h b/constants.h index 4b744d20..06284f2c 100644 --- a/constants.h +++ b/constants.h @@ -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. diff --git a/monitor.c b/monitor.c index 3024b6c1..1771eddb 100644 --- a/monitor.c +++ b/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) { + // 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 { 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"); diff --git a/overlay.c b/overlay.c index ed9239c9..3a29366c 100644 --- a/overlay.c +++ b/overlay.c @@ -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; } diff --git a/overlay_abbreviations.c b/overlay_abbreviations.c index 48cc12ec..197534e9 100644 --- a/overlay_abbreviations.c +++ b/overlay_abbreviations.c @@ -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,15 +264,13 @@ 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;inode) 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; } diff --git a/overlay_advertise.c b/overlay_advertise.c index 01c90d2b..f0ebea6c 100644 --- a/overlay_advertise.c +++ b/overlay_advertise.c @@ -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,51 +140,17 @@ int overlay_route_add_advertisements(overlay_buffer *e) slots--; slots_used++; } - - while(slots>0) - { - /* find next node */ - int bin=oad_bin; - int slot=oad_slot; - - /* XXX Skipping priority advertised nodes could be done faster, e.g., - by adding a flag to the overlay_node structure to indicate if it - has been sent priority, and if so, skip it. - The flags could then be reset at the end of this function. - But this will do for now. - */ - int skip=0; - for(i=0;isid,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; - } +*/ + struct subscriber *start = last_advertised; + // append announcements starting from the last node we advertised + enum_subscribers(start, add_advertisement, e); + + // 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); return 0; @@ -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(ofspayload->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], - i, - /* time range that this advertisement covers. - XXX - Make it up for now. */ - now-2500,now, - score,gateways_en_route); - } + /* File it */ + 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);; } diff --git a/overlay_mdp.c b/overlay_mdp.c index e2997f73..84a9d84a 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #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; } diff --git a/overlay_packetformats.c b/overlay_packetformats.c index 3143f48b..8d4b13c6 100644 --- a/overlay_packetformats.c +++ b/overlay_packetformats.c @@ -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. diff --git a/overlay_payload.c b/overlay_payload.c index f14be10f..6d9837b7 100644 --- a/overlay_payload.c +++ b/overlay_payload.c @@ -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); diff --git a/overlay_route.c b/overlay_route.c index 666a4fe5..06027627 100644 --- a/overlay_route.c +++ b/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. - - 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. -*/ +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 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=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;iscores[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_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 || prefixLennode) && 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", alloca_tohex_sid(sid)); } - - bcopy(sid, overlay_nodes[bin_number][free_slot].sid, SID_SIZE); - - // 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); - - 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;oobservations[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;ineighbour_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;oobservations[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;icorrected_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_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;nalarm = 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,118 +1071,87 @@ 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; - mdp->nodeinfo.neighbourP=0; - mdp->nodeinfo.time_since_last_observation = 0; - mdp->nodeinfo.score=256; - mdp->nodeinfo.interface_number=-1; - bcopy(&keyring->contexts[cn]->identities[in] - ->keypairs[kp]->public_key[0], - &mdp->nodeinfo.sid[0],SID_SIZE); - - mdp->nodeinfo.did[0]=0; - if (mdp->nodeinfo.resolve_did) { - mdp->nodeinfo.resolve_did=0; - int k2; - for(k2=0;k2contexts[cn]->identities[in] - ->keypair_count;k2++) - if (keyring->contexts[cn]->identities[in]->keypairs[k2]->type - ==KEYTYPE_DID) - { - /* private key field has unpacked did */ - bcopy(&keyring->contexts[cn]->identities[in] - ->keypairs[k2]->private_key[0], - &mdp->nodeinfo.did[0], - keyring->contexts[cn]->identities[in] - ->keypairs[k2]->private_key_len); - /* public key has name */ - bcopy(&keyring->contexts[cn]->identities[in] - ->keypairs[k2]->public_key[0], - &mdp->nodeinfo.name[0], - keyring->contexts[cn]->identities[in] - ->keypairs[k2]->public_key_len); - mdp->nodeinfo.resolve_did=1; - } - } - } - mdp->nodeinfo.count++; - } - } - - /* check neighbour table, i.e., if directly connected */ - for(n=0;nnodeinfo.sid[0], - &overlay_neighbours[n].node->sid[0], - mdp->nodeinfo.sid_prefix_length/2)) - { - if (mdp->nodeinfo.count==mdp->nodeinfo.index) { 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; - int i; - for(i=0;imdp->nodeinfo.score) - { - mdp->nodeinfo.score=overlay_neighbours[n].scores[i]; - 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;binnodeinfo.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; + mdp->nodeinfo.localP=1; mdp->nodeinfo.neighbourP=0; - mdp->nodeinfo.time_since_last_observation = gettime_ms(); - mdp->nodeinfo.score=-1; + mdp->nodeinfo.time_since_last_observation = 0; + mdp->nodeinfo.score=256; mdp->nodeinfo.interface_number=-1; - mdp->nodeinfo.resolve_did=0; - int o; - for(o=0;ocorrected_score>mdp->nodeinfo.score) { - mdp->nodeinfo.score=ob->corrected_score; - } - if (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], + bcopy(&keyring->contexts[cn]->identities[in] + ->keypairs[kp]->public_key[0], &mdp->nodeinfo.sid[0],SID_SIZE); + + mdp->nodeinfo.did[0]=0; + if (mdp->nodeinfo.resolve_did) { + mdp->nodeinfo.resolve_did=0; + int k2; + for(k2=0;k2contexts[cn]->identities[in] + ->keypair_count;k2++) + if (keyring->contexts[cn]->identities[in]->keypairs[k2]->type + ==KEYTYPE_DID) + { + /* private key field has unpacked did */ + bcopy(&keyring->contexts[cn]->identities[in] + ->keypairs[k2]->private_key[0], + &mdp->nodeinfo.did[0], + keyring->contexts[cn]->identities[in] + ->keypairs[k2]->private_key_len); + /* public key has name */ + bcopy(&keyring->contexts[cn]->identities[in] + ->keypairs[k2]->public_key[0], + &mdp->nodeinfo.name[0], + keyring->contexts[cn]->identities[in] + ->keypairs[k2]->public_key_len); + mdp->nodeinfo.resolve_did=1; + } + } + return overlay_mdp_reply(mdp_named.poll.fd,addr,addrlen,mdp); } - mdp->nodeinfo.count++; } - } + + 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.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;imdp->nodeinfo.score) + { + mdp->nodeinfo.score=overlay_neighbours[n].scores[i]; + mdp->nodeinfo.interface_number=i; + } + + }else{ + mdp->nodeinfo.neighbourP=0; + mdp->nodeinfo.time_since_last_observation = -1; + int o; + for(o=0;oobservations[o].observed_score) + { + overlay_node_observation *ob + =&node->observations[o]; + if (ob->corrected_score>mdp->nodeinfo.score) { + mdp->nodeinfo.score=ob->corrected_score; + } + 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; + } + } + } return overlay_mdp_reply(mdp_named.poll.fd,addr,addrlen,mdp); } diff --git a/serval.h b/serval.h index 55624844..c438f747 100644 --- a/serval.h +++ b/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 { diff --git a/subscribers.c b/subscribers.c index 292d7128..eb77a6c0 100644 --- a/subscribers.c +++ b/subscribers.c @@ -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<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); } diff --git a/subscribers.h b/subscribers.h index 5e6a44ec..ede0517b 100644 --- a/subscribers.h +++ b/subscribers.h @@ -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