Track incoming neighbour links w. multiple common interfaces

This commit is contained in:
Jeremy Lakeman 2013-04-30 14:06:48 +09:30
parent 4e48725c93
commit c6a9564dc3

View File

@ -45,10 +45,25 @@ struct link{
// calculated path score;
int hop_count;
// loop prevention;
char calculating;
};
struct neighbour_link{
struct neighbour_link *_next;
// which of their interfaces are these stats for?
int neighbour_interface;
// which interface did we hear it on?
struct overlay_interface *interface;
// very simple time based link up/down detection;
// when will we consider the link broken?
time_ms_t neighbour_unicast_receive_timeout;
time_ms_t neighbour_broadcast_receive_timeout;
};
struct neighbour{
struct neighbour *_next;
@ -57,24 +72,20 @@ struct neighbour{
// whenever we hear about a link change, update the version to mark all link path scores as dirty
char path_version;
// when do we assume the link is dead because they can't hear us?
// when do we assume the link is dead because they stopped hearing us or vice versa?
time_ms_t neighbour_link_timeout;
// which of our interfaces did they hear us from?
struct overlay_interface *interface;
// which of their interfaces have we heard them sending from?
int neighbour_interface;
char neighbour_version;
// when will we consider the link broken?
time_ms_t neighbour_unicast_receive_timeout;
time_ms_t neighbour_broadcast_receive_timeout;
// next link update
time_ms_t next_neighbour_update;
// un-balanced tree of known link states
struct link *root;
// list of incoming link stats
struct neighbour_link *links, *best_link;
// whenever we pick a different link or the stats change in a way everyone needs to know ASAP, update the version
char version;
};
// one struct per subscriber, where we track all routing information, allocated on first use
@ -350,6 +361,14 @@ static void free_neighbour(struct neighbour **neighbour_ptr){
struct neighbour *n = *neighbour_ptr;
if (config.debug.linkstate)
DEBUGF("LINK STATE; neighbour connection timed out %s", alloca_tohex_sid(n->subscriber->sid));
struct neighbour_link *link = n->links;
while(link){
struct neighbour_link *l=link;
link = l->_next;
free(l);
}
free_links(n->root);
n->root=NULL;
*neighbour_ptr = n->_next;
@ -357,35 +376,65 @@ static void free_neighbour(struct neighbour **neighbour_ptr){
route_version++;
}
static int link_send_neighbours(struct overlay_buffer *payload){
static void clean_neighbours(time_ms_t now)
{
struct neighbour **n_ptr = &neighbours;
time_ms_t now = gettime_ms();
while (*n_ptr){
struct neighbour *n = *n_ptr;
if (n->neighbour_unicast_receive_timeout <now && n->neighbour_broadcast_receive_timeout < now){
// If we haven't heard any packets from this neighbour, free the struct as we go.
struct neighbour_link **list = &n->links;
while(*list){
struct neighbour_link *link = *list;
if (link->interface->state!=INTERFACE_STATE_UP ||
(link->neighbour_unicast_receive_timeout < now && link->neighbour_broadcast_receive_timeout < now)){
*list=link->_next;
free(link);
}else{
list = &link->_next;
}
}
if (!n->links){
free_neighbour(n_ptr);
}else{
char flags=0;
if (n->neighbour_unicast_receive_timeout >= now)
flags|=FLAG_UNICAST;
if (n->neighbour_broadcast_receive_timeout >= now)
flags|=FLAG_BROADCAST;
if (n->next_neighbour_update - INCLUDE_ANYWAY <= now){
if (append_link_state(payload, flags, n->subscriber, my_subscriber, n->neighbour_interface, n->neighbour_version)){
link_send_alarm.alarm = now;
return 1;
}
n->next_neighbour_update = now + LINK_NEIGHBOUR_INTERVAL;
}
if (n->next_neighbour_update < link_send_alarm.alarm)
link_send_alarm.alarm = n->next_neighbour_update;
n_ptr = &(n->_next);
n_ptr = &n->_next;
}
}
}
static int link_send_neighbours(struct overlay_buffer *payload)
{
time_ms_t now = gettime_ms();
clean_neighbours(now);
struct neighbour *n = neighbours;
while (n){
// TODO actually compare links to find the best...
struct neighbour_link *best_link=n->links;
if (n->best_link != best_link){
n->best_link = best_link;
n->version ++;
n->next_neighbour_update = now;
}
char flags=0;
if (best_link->neighbour_unicast_receive_timeout >= now)
flags|=FLAG_UNICAST;
if (best_link->neighbour_broadcast_receive_timeout >= now)
flags|=FLAG_BROADCAST;
if (n->next_neighbour_update - INCLUDE_ANYWAY <= now){
if (append_link_state(payload, flags, n->subscriber, my_subscriber, best_link->neighbour_interface, n->version)){
link_send_alarm.alarm = now;
return 1;
}
n->next_neighbour_update = now + best_link->interface->tick_ms;
}
if (n->next_neighbour_update < link_send_alarm.alarm)
link_send_alarm.alarm = n->next_neighbour_update;
n = n->_next;
}
return 0;
}
@ -428,31 +477,46 @@ static void update_alarm(time_ms_t limit){
}
}
struct neighbour_link * get_neighbour_link(struct neighbour *neighbour, struct overlay_interface *interface, int sender_interface)
{
struct neighbour_link *link = neighbour->links;
while(link){
if (link->interface == interface && link->neighbour_interface == sender_interface)
return link;
link=link->_next;
}
link = emalloc_zero(sizeof(struct neighbour_link));
link->interface = interface;
link->neighbour_interface = sender_interface;
link->_next = neighbour->links;
neighbour->links = link;
return link;
}
// track stats for receiving packets from this neighbour
int link_received_packet(struct subscriber *subscriber, struct overlay_interface *interface, int sender_interface, int sender_seq, int unicast)
{
struct neighbour *n = get_neighbour(subscriber, 1);
struct neighbour *neighbour = get_neighbour(subscriber, 1);
struct neighbour_link *link=get_neighbour_link(neighbour, interface, sender_interface);
time_ms_t now = gettime_ms();
// for now we'll use a simple time based link up/down flag
// force an update when we start hearing a new neighbour link
if (unicast){
if (n->neighbour_unicast_receive_timeout < now){
n->next_neighbour_update = now;
n->neighbour_version++;
if (link->neighbour_unicast_receive_timeout < now){
neighbour->next_neighbour_update = now;
neighbour->version++;
update_alarm(now);
}
n->neighbour_unicast_receive_timeout = now + LINK_EXPIRY;
link->neighbour_unicast_receive_timeout = now + LINK_EXPIRY;
}else{
if (n->neighbour_broadcast_receive_timeout < now){
n->next_neighbour_update = now;
n->neighbour_version++;
if (link->neighbour_broadcast_receive_timeout < now){
neighbour->next_neighbour_update = now;
neighbour->version++;
update_alarm(now);
}
n->neighbour_broadcast_receive_timeout = now + LINK_EXPIRY;
link->neighbour_broadcast_receive_timeout = now + (interface->tick_ms * 3);
}
// TODO track each sender interface independently?
n->neighbour_interface = sender_interface;
n->interface = interface;
return 0;
}
@ -563,12 +627,5 @@ void link_explained(struct subscriber *subscriber)
void link_interface_down(struct overlay_interface *interface)
{
struct neighbour **n_ptr = &neighbours;
while(*n_ptr){
if ((*n_ptr)->interface == interface){
free_neighbour(n_ptr);
}else{
n_ptr = &((*n_ptr)->_next);
}
}
clean_neighbours(gettime_ms());
}