mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-19 11:16:35 +00:00
Only compare routes that have all links via the same neighbour
This commit is contained in:
parent
d7caaf4973
commit
559b270966
@ -63,6 +63,7 @@ static int mark_subscriber_down(struct subscriber *subscriber, void *context)
|
||||
|
||||
static void
|
||||
overlay_interface_close(overlay_interface *interface){
|
||||
link_interface_down(interface);
|
||||
enum_subscribers(NULL, mark_subscriber_down, interface);
|
||||
INFOF("Interface %s addr %s is down", interface->name, inet_ntoa(interface->broadcast_address.sin_addr));
|
||||
unschedule(&interface->alarm);
|
||||
|
@ -306,7 +306,7 @@ int parseEnvelopeHeader(struct decode_context *context, struct overlay_interface
|
||||
context->sender->last_acked = now;
|
||||
}
|
||||
|
||||
link_received_packet(context->sender, sender_interface, sender_seq, packet_flags & PACKET_UNICAST);
|
||||
link_received_packet(context->sender, interface, sender_interface, sender_seq, packet_flags & PACKET_UNICAST);
|
||||
}
|
||||
|
||||
if (addr){
|
||||
|
131
route_link.c
131
route_link.c
@ -60,7 +60,7 @@ struct neighbour{
|
||||
// when do we assume the link is dead because they can't hear us?
|
||||
time_ms_t neighbour_link_timeout;
|
||||
// which of our interfaces did they hear us from?
|
||||
int our_interface;
|
||||
struct overlay_interface *interface;
|
||||
|
||||
// which of their interfaces have we heard them sending from?
|
||||
int neighbour_interface;
|
||||
@ -83,6 +83,8 @@ struct link_state{
|
||||
struct subscriber *next_hop;
|
||||
struct subscriber *transmitter;
|
||||
int hop_count;
|
||||
int route_version;
|
||||
char calculating;
|
||||
|
||||
// when do we need to send a new link state message.
|
||||
time_ms_t next_update;
|
||||
@ -99,12 +101,14 @@ static struct sched_ent link_send_alarm={
|
||||
};
|
||||
|
||||
struct neighbour *neighbours;
|
||||
|
||||
int route_version=0;
|
||||
|
||||
static struct link_state *get_link_state(struct subscriber *subscriber)
|
||||
{
|
||||
if (!subscriber->link_state)
|
||||
if (!subscriber->link_state){
|
||||
subscriber->link_state = emalloc_zero(sizeof(struct link_state));
|
||||
subscriber->link_state->route_version = route_version -1;
|
||||
}
|
||||
return subscriber->link_state;
|
||||
}
|
||||
|
||||
@ -138,14 +142,16 @@ static void free_links(struct link *link)
|
||||
free(link);
|
||||
}
|
||||
|
||||
static struct link *find_link(struct neighbour *neighbour, struct subscriber *receiver)
|
||||
static struct link *find_link(struct neighbour *neighbour, struct subscriber *receiver, char create)
|
||||
{
|
||||
struct link **link_ptr=&neighbour->root, *link=neighbour->root;
|
||||
while(1){
|
||||
if (link==NULL){
|
||||
link = *link_ptr = emalloc_zero(sizeof(struct link));
|
||||
link->receiver = receiver;
|
||||
link->path_version = neighbour->path_version -1;
|
||||
if (create){
|
||||
link = *link_ptr = emalloc_zero(sizeof(struct link));
|
||||
link->receiver = receiver;
|
||||
link->path_version = neighbour->path_version -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (receiver == link->receiver)
|
||||
@ -167,7 +173,7 @@ static struct link *get_parent(struct neighbour *neighbour, struct link *link)
|
||||
return NULL;
|
||||
|
||||
if (!link->parent)
|
||||
link->parent = find_link(neighbour, link->transmitter);
|
||||
link->parent = find_link(neighbour, link->transmitter, 0);
|
||||
|
||||
return link->parent;
|
||||
}
|
||||
@ -182,7 +188,8 @@ static void update_path_score(struct neighbour *neighbour, struct link *link){
|
||||
int hop_count = -1;
|
||||
|
||||
if (link->transmitter == my_subscriber){
|
||||
hop_count = 1;
|
||||
if (link->receiver==neighbour->subscriber)
|
||||
hop_count = 1;
|
||||
}else{
|
||||
struct link *parent = get_parent(neighbour, link);
|
||||
if (parent && (!parent->calculating)){
|
||||
@ -193,45 +200,74 @@ static void update_path_score(struct neighbour *neighbour, struct link *link){
|
||||
}
|
||||
}
|
||||
|
||||
if (config.debug.verbose && config.debug.linkstate && hop_count != link->hop_count)
|
||||
DEBUGF("LINK STATE; path score to %s via %s version %d = %d",
|
||||
alloca_tohex_sid(link->receiver->sid),
|
||||
alloca_tohex_sid(neighbour->subscriber->sid),
|
||||
neighbour->path_version,
|
||||
hop_count);
|
||||
|
||||
link->hop_count = hop_count;
|
||||
link->path_version = neighbour->path_version;
|
||||
link->calculating = 0;
|
||||
}
|
||||
|
||||
static int find_best_link(struct subscriber *subscriber, struct neighbour **best_neighbour, struct link **best_link)
|
||||
static int find_best_link(struct subscriber *subscriber)
|
||||
{
|
||||
struct link_state *state = get_link_state(subscriber);
|
||||
if (state->route_version == route_version)
|
||||
return 0;
|
||||
|
||||
if (state->calculating)
|
||||
return -1;
|
||||
state->calculating = 1;
|
||||
|
||||
struct neighbour *neighbour = neighbours;
|
||||
int best_hop_count = 99;
|
||||
struct subscriber *next_hop = NULL, *transmitter=NULL;
|
||||
time_ms_t now = gettime_ms();
|
||||
|
||||
while (neighbour){
|
||||
struct link *link = find_link(neighbour, subscriber);
|
||||
if (neighbour->neighbour_link_timeout >= now){
|
||||
update_path_score(neighbour, link);
|
||||
if (link->hop_count>0 && link->hop_count < best_hop_count){
|
||||
next_hop = neighbour->subscriber;
|
||||
best_hop_count = link->hop_count;
|
||||
transmitter = link->transmitter;
|
||||
if (best_link)
|
||||
*best_link = link;
|
||||
if (best_neighbour)
|
||||
*best_neighbour = neighbour;
|
||||
}
|
||||
if (neighbour->neighbour_link_timeout < now)
|
||||
goto next;
|
||||
|
||||
struct link *link = find_link(neighbour, subscriber, 0);
|
||||
if (!(link && link->transmitter))
|
||||
goto next;
|
||||
|
||||
if (link->transmitter != my_subscriber){
|
||||
struct link_state *parent_state = get_link_state(link->transmitter);
|
||||
find_best_link(link->transmitter);
|
||||
if (parent_state->next_hop != neighbour->subscriber)
|
||||
goto next;
|
||||
}
|
||||
|
||||
update_path_score(neighbour, link);
|
||||
if (link->hop_count>0 && link->hop_count < best_hop_count){
|
||||
next_hop = neighbour->subscriber;
|
||||
best_hop_count = link->hop_count;
|
||||
transmitter = link->transmitter;
|
||||
}
|
||||
|
||||
next:
|
||||
neighbour = neighbour->_next;
|
||||
}
|
||||
|
||||
if (state->next_hop != next_hop || state->transmitter != transmitter){
|
||||
if (config.debug.linkstate)
|
||||
DEBUGF("LINK STATE; next hop for %s is now %s", alloca_tohex_sid(subscriber->sid), next_hop?alloca_tohex_sid(next_hop->sid):"UNREACHABLE");
|
||||
DEBUGF("LINK STATE; next hop for %s is now %d hops, %s via %s",
|
||||
alloca_tohex_sid(subscriber->sid),
|
||||
best_hop_count,
|
||||
next_hop?alloca_tohex_sid(next_hop->sid):"UNREACHABLE",
|
||||
transmitter?alloca_tohex_sid(transmitter->sid):"NONE");
|
||||
state->next_update = now;
|
||||
}
|
||||
|
||||
state->next_hop = next_hop;
|
||||
state->transmitter = transmitter;
|
||||
state->hop_count = best_hop_count;
|
||||
state->route_version = route_version;
|
||||
state->calculating = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -285,8 +321,7 @@ static int append_link(struct subscriber *subscriber, void *context)
|
||||
|
||||
time_ms_t now = gettime_ms();
|
||||
|
||||
struct link *link = NULL;
|
||||
find_best_link(subscriber, NULL, &link);
|
||||
find_best_link(subscriber);
|
||||
|
||||
if (state->next_update - INCLUDE_ANYWAY <= now){
|
||||
if (subscriber->reachable==REACHABLE_SELF){
|
||||
@ -297,7 +332,7 @@ static int append_link(struct subscriber *subscriber, void *context)
|
||||
}
|
||||
} else {
|
||||
|
||||
if (append_link_state(payload, 0, link?link->transmitter:NULL, subscriber, -1, 0)){
|
||||
if (append_link_state(payload, 0, state->transmitter, subscriber, -1, 0)){
|
||||
link_send_alarm.alarm = now;
|
||||
return 1;
|
||||
}
|
||||
@ -311,6 +346,17 @@ static int append_link(struct subscriber *subscriber, void *context)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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));
|
||||
free_links(n->root);
|
||||
n->root=NULL;
|
||||
*neighbour_ptr = n->_next;
|
||||
free(n);
|
||||
route_version++;
|
||||
}
|
||||
|
||||
static int link_send_neighbours(struct overlay_buffer *payload){
|
||||
struct neighbour **n_ptr = &neighbours;
|
||||
time_ms_t now = gettime_ms();
|
||||
@ -319,12 +365,7 @@ static int link_send_neighbours(struct overlay_buffer *payload){
|
||||
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.
|
||||
if (config.debug.linkstate)
|
||||
DEBUGF("LINK STATE; neighbour connection timed out %s", alloca_tohex_sid(n->subscriber->sid));
|
||||
free_links(n->root);
|
||||
n->root=NULL;
|
||||
*n_ptr = n->_next;
|
||||
free(n);
|
||||
free_neighbour(n_ptr);
|
||||
}else{
|
||||
char flags=0;
|
||||
if (n->neighbour_unicast_receive_timeout >= now)
|
||||
@ -365,8 +406,9 @@ static void link_send(struct sched_ent *alarm)
|
||||
ob_checkpoint(frame->payload);
|
||||
int pos = ob_position(frame->payload);
|
||||
|
||||
if (link_send_neighbours(frame->payload)==0)
|
||||
if (link_send_neighbours(frame->payload)==0){
|
||||
enum_subscribers(NULL, append_link, frame->payload);
|
||||
}
|
||||
|
||||
ob_rewind(frame->payload);
|
||||
|
||||
@ -387,7 +429,7 @@ static void update_alarm(time_ms_t limit){
|
||||
}
|
||||
|
||||
// track stats for receiving packets from this neighbour
|
||||
int link_received_packet(struct subscriber *subscriber, int sender_interface, int sender_seq, int unicast)
|
||||
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);
|
||||
time_ms_t now = gettime_ms();
|
||||
@ -410,6 +452,7 @@ int link_received_packet(struct subscriber *subscriber, int sender_interface, in
|
||||
}
|
||||
// TODO track each sender interface independently?
|
||||
n->neighbour_interface = sender_interface;
|
||||
n->interface = interface;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -465,6 +508,7 @@ int link_receive(overlay_mdp_frame *mdp)
|
||||
// ignore any links that our neighbour is using to route through us.
|
||||
if (receiver == my_subscriber)
|
||||
continue;
|
||||
|
||||
if (receiver == sender){
|
||||
// who can our neighbour hear?
|
||||
|
||||
@ -481,10 +525,11 @@ int link_receive(overlay_mdp_frame *mdp)
|
||||
neighbour->neighbour_link_timeout = now + LINK_INTERVAL;
|
||||
}else
|
||||
continue;
|
||||
}
|
||||
}else if(transmitter == my_subscriber)
|
||||
transmitter = NULL;
|
||||
|
||||
struct link *link = find_link(neighbour, receiver);
|
||||
if (link->transmitter != transmitter || link->link_version != version){
|
||||
struct link *link = find_link(neighbour, receiver, transmitter?1:0);
|
||||
if (link && (link->transmitter != transmitter || link->link_version != version)){
|
||||
changed = 1;
|
||||
link->transmitter = transmitter;
|
||||
link->link_version = version;
|
||||
@ -495,6 +540,7 @@ int link_receive(overlay_mdp_frame *mdp)
|
||||
send_please_explain(&context, my_subscriber, sender);
|
||||
|
||||
if (changed){
|
||||
route_version++;
|
||||
neighbour->path_version ++;
|
||||
if (link_send_alarm.alarm>now || link_send_alarm.alarm==0){
|
||||
unschedule(&link_send_alarm);
|
||||
@ -515,3 +561,14 @@ void link_explained(struct subscriber *subscriber)
|
||||
update_alarm(now);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
3
serval.h
3
serval.h
@ -867,8 +867,9 @@ extern long long bundles_available;
|
||||
extern char crash_handler_clue[1024];
|
||||
|
||||
|
||||
int link_received_packet(struct subscriber *subscriber, int sender_interface, int sender_seq, int unicode);
|
||||
int link_received_packet(struct subscriber *subscriber, struct overlay_interface *interface, int sender_interface, int sender_seq, int unicode);
|
||||
int link_receive(overlay_mdp_frame *mdp);
|
||||
void link_explained(struct subscriber *subscriber);
|
||||
void link_interface_down(struct overlay_interface *interface);
|
||||
|
||||
#endif // __SERVALD_SERVALD_H
|
||||
|
@ -44,7 +44,6 @@ start_routing_instance() {
|
||||
set log.console.show_time on \
|
||||
set debug.mdprequests yes \
|
||||
set debug.linkstate yes \
|
||||
set debug.verbose yes \
|
||||
set rhizome.enable no
|
||||
start_servald_server
|
||||
wait_until interface_up
|
||||
@ -274,6 +273,71 @@ test_multihop_linear() {
|
||||
assertStdoutGrep --matches=1 "^$SIDD:INDIRECT :"
|
||||
}
|
||||
|
||||
setup_offline() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B +C +D create_single_identity
|
||||
foreach_instance +A +B +C add_interface 1
|
||||
foreach_instance +A +B +D add_interface 2
|
||||
foreach_instance +A +B +C +D start_routing_instance
|
||||
}
|
||||
|
||||
instance_offline() {
|
||||
local I N
|
||||
for I; do
|
||||
[ $I = $instance_arg ] && continue
|
||||
for ((N=1; 1; ++N)); do
|
||||
local sidvar=SID${I#+}$N
|
||||
[ -n "${!sidvar}" ] || break
|
||||
if ! grep "LINK STATE.*${!sidvar}.*UNREACHABLE" $instance_servald_log; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
doc_offline="One node going offline"
|
||||
test_offline() {
|
||||
foreach_instance +A +B +C +D \
|
||||
wait_until has_seen_instances +A +B +C +D
|
||||
stop_servald_server +C
|
||||
foreach_instance +A +B +D \
|
||||
wait_until --timeout=30 instance_offline +C
|
||||
}
|
||||
|
||||
setup_circle() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B +C +D +E +F +G +H create_single_identity
|
||||
foreach_instance +A +B add_interface 1
|
||||
foreach_instance +B +C add_interface 2
|
||||
foreach_instance +C +D add_interface 3
|
||||
foreach_instance +D +E add_interface 4
|
||||
foreach_instance +E +F add_interface 5
|
||||
foreach_instance +F +G add_interface 6
|
||||
foreach_instance +G +H add_interface 7
|
||||
foreach_instance +H +A add_interface 8
|
||||
foreach_instance +A +B +C +D +E +F +G +H start_routing_instance
|
||||
}
|
||||
|
||||
doc_circle="Circle of nodes with one going offline"
|
||||
test_circle() {
|
||||
foreach_instance +A +B +C +D +E +F +G +H \
|
||||
wait_until has_seen_instances +A +B +C +D +E +F +G +H
|
||||
set_instance +A
|
||||
executeOk_servald mdp ping --timeout=3 $SIDC 1
|
||||
tfw_cat --stdout --stderr
|
||||
executeOk_servald route print
|
||||
assertStdoutGrep --matches=1 "^$SIDC:INDIRECT :"
|
||||
stop_servald_server +B
|
||||
foreach_instance +A +C +D +E +F +G +H \
|
||||
wait_until --timeout=20 instance_offline +B
|
||||
executeOk_servald mdp ping --timeout=3 $SIDC 1
|
||||
tfw_cat --stdout --stderr
|
||||
executeOk_servald route print
|
||||
assertStdoutGrep --matches=1 "^$SIDC:INDIRECT :"
|
||||
}
|
||||
|
||||
setup_crowded_mess() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
|
Loading…
Reference in New Issue
Block a user