Route mulit-hop via unicast links

This commit is contained in:
Jeremy Lakeman 2013-08-09 16:19:45 +09:30
parent 55657623aa
commit 9a50d8a9ef
8 changed files with 118 additions and 102 deletions

View File

@ -262,11 +262,11 @@ static int add_explain_response(struct subscriber *subscriber, void *context){
// if one of our identities is unknown,
// the header of this packet must include our full sid.
if (subscriber->reachable==REACHABLE_SELF){
subscriber->send_full=1;
if (subscriber==my_subscriber){
response->please_explain->source_full=1;
return 0;
}
subscriber->send_full=1;
}
// add the whole subscriber id to the payload, stop if we run out of space
@ -399,11 +399,11 @@ int send_please_explain(struct decode_context *context, struct subscriber *sourc
if (!context->sender)
frame->source_full=1;
if (destination && (destination->reachable & REACHABLE)){
if (destination){
frame->ttl = PAYLOAD_TTL_DEFAULT; // MAX?
frame->destination = destination;
frame->source_full=1;
}else{
DEBUGF("Need to send explanation to destination that isn't routable");
// send both a broadcast & unicast response out the same interface this packet arrived on.
frame->ttl=1;// how will this work with olsr??
if (context->interface){

View File

@ -51,6 +51,8 @@ struct overlay_frame {
time_ms_t delay_until;
struct packet_destination destinations[MAX_PACKET_DESTINATIONS];
int destination_count;
int transmit_count;
// each payload gets a sequence number that is reused on retransmission
int32_t mdp_sequence;

View File

@ -303,6 +303,9 @@ int parseEnvelopeHeader(struct decode_context *context, struct overlay_interface
RETURN(1);
}
if (context->packet_version > context->sender->max_packet_version)
context->sender->max_packet_version=context->packet_version;
if (interface->point_to_point && interface->other_device!=context->sender){
INFOF("Established point to point link with %s on %s", alloca_tohex_sid(context->sender->sid), interface->name);
context->point_to_point_device = context->interface->other_device = context->sender;

View File

@ -152,19 +152,6 @@ int overlay_payload_enqueue(struct overlay_frame *p)
if (!p) return WHY("Cannot queue NULL");
do{
if (p->destination_count>0)
break;
if (!p->destination)
break;
if (p->destination->reachable&REACHABLE)
break;
if (directory_service&&directory_service->reachable&REACHABLE)
break;
return WHYF("Cannot send %x packet, destination %s is unreachable", p->type,
alloca_tohex_sid(p->destination->sid));
} while(0);
if (p->queue>=OQ_MAX)
return WHY("Invalid queue specified");
@ -199,7 +186,7 @@ int overlay_payload_enqueue(struct overlay_frame *p)
// hook to allow for flooding via olsr
olsr_send(p);
link_add_broadcast_destinations(p);
link_add_destinations(p);
// just drop it now
if (p->destination_count == 0){
@ -311,15 +298,9 @@ overlay_calc_queue_time(overlay_txqueue *queue, struct overlay_frame *frame){
return 0;
}
}else{
// ignore payload alarm if the destination is currently unreachable
if (!frame->destination){
return 0;
}
if (!(frame->destination->reachable&REACHABLE)){
if (!directory_service || !(directory_service->reachable&REACHABLE)){
return 0;
}
}
}
if (next_allowed_packet < frame->delay_until)
@ -366,38 +347,12 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
if (packet->buffer && ob_limit(frame->payload) > ob_remaining(packet->buffer))
goto skip;
if (frame->destination_count==0){
frame->next_hop = frame->destination;
if (frame->destination_count==0 && frame->destination){
link_add_destinations(frame);
if (frame->next_hop){
// Where do we need to route this payload next?
int r = frame->next_hop->reachable;
// first, should we try to bounce this payload off the directory service?
if (r==REACHABLE_NONE &&
directory_service &&
frame->next_hop!=directory_service){
frame->next_hop=directory_service;
r=directory_service->reachable;
}
// do we need to route via a neighbour?
if (r&REACHABLE_INDIRECT){
frame->next_hop = frame->next_hop->next_hop;
r = frame->next_hop->reachable;
}
if (!(r&REACHABLE_DIRECT)){
goto skip;
}
frame->destinations[frame->destination_count++].destination=add_destination_ref(frame->next_hop->destination);
// degrade packet version if required to reach the destination
if (frame->packet_version > frame->next_hop->max_packet_version)
frame->packet_version = frame->next_hop->max_packet_version;
}
// degrade packet version if required to reach the destination
if (frame->packet_version > frame->next_hop->max_packet_version)
frame->packet_version = frame->next_hop->max_packet_version;
}
int destination_index=-1;
@ -485,7 +440,8 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
}
frame->destinations[destination_index].delay_until = now+200;
frame->transmit_count++;
if (config.debug.overlayframes){
DEBUGF("Appended payload %p, %d type %x len %d for %s via %s",
frame, frame->mdp_sequence,
@ -495,8 +451,9 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
}
// dont retransmit if we aren't sending sequence numbers, or we've been asked not to
if (frame->packet_version<1 || frame->resend<=0 ||
frame->enqueued_at + queue->latencyTarget < frame->destinations[destination_index].delay_until){
if (frame->packet_version<1 || frame->resend<=0 || packet->seq==-1){
if (config.debug.overlayframes)
DEBUGF("Not waiting for retransmission (%d, %d, %d)", frame->packet_version, frame->resend, packet->seq);
remove_destination(frame, destination_index);
if (frame->destination_count==0){
frame = overlay_queue_remove(queue, frame);

View File

@ -777,7 +777,7 @@ static int link_send_neighbours()
struct link_out *out = n->out_links;
while(out){
if (out->destination->unicast){
if (out->destination->tick_ms>0 && out->destination->unicast){
if (out->destination->last_tx + out->destination->tick_ms < now)
overlay_send_tick_packet(out->destination);
if (out->destination->last_tx + out->destination->tick_ms < link_send_alarm.alarm)
@ -871,31 +871,63 @@ struct link_in * get_neighbour_link(struct neighbour *neighbour, struct overlay_
return link;
}
int link_add_broadcast_destinations(struct overlay_frame *frame)
int link_add_destinations(struct overlay_frame *frame)
{
char added_interface[OVERLAY_MAX_INTERFACES];
bzero(added_interface, sizeof(added_interface));
struct neighbour *neighbour = neighbours;
for(;neighbour;neighbour = neighbour->_next){
if (neighbour->subscriber->reachable&REACHABLE_DIRECT){
struct network_destination *dest = neighbour->subscriber->destination;
// TODO set packet version per destination
if (frame->packet_version > neighbour->subscriber->max_packet_version)
frame->packet_version = neighbour->subscriber->max_packet_version;
if (!dest->unicast){
// make sure we only add broadcast interfaces once
int id = dest->interface - overlay_interfaces;
if (added_interface[id]){
continue;
if (frame->destination){
frame->next_hop = frame->destination;
// if the destination is unreachable, but we have a reachable directory service
// forward it through the directory service
if (frame->next_hop->reachable==REACHABLE_NONE
&& directory_service
&& frame->next_hop!=directory_service
&& directory_service->reachable&REACHABLE)
frame->next_hop = directory_service;
if (frame->next_hop->reachable==REACHABLE_NONE){
// if the destination is a neighbour, add all probable destinations
struct neighbour *n = get_neighbour(frame->destination, 0);
if (n){
struct link_out *out = n->out_links;
while(out){
frame->destinations[frame->destination_count++].destination = add_destination_ref(out->destination);
out = out->_next;
}
}
frame->destinations[frame->destination_count++].destination=add_destination_ref(dest);
}
if ((frame->next_hop->reachable&REACHABLE)==REACHABLE_INDIRECT)
frame->next_hop = frame->next_hop->next_hop;
if (frame->next_hop->reachable&REACHABLE_DIRECT){
if (frame->destination_count < MAX_PACKET_DESTINATIONS)
frame->destinations[frame->destination_count++].destination=add_destination_ref(frame->next_hop->destination);
}
}else{
char added_interface[OVERLAY_MAX_INTERFACES];
bzero(added_interface, sizeof(added_interface));
struct neighbour *neighbour = neighbours;
for(;neighbour;neighbour = neighbour->_next){
if (neighbour->subscriber->reachable&REACHABLE_DIRECT){
struct network_destination *dest = neighbour->subscriber->destination;
// TODO set packet version per destination
if (frame->packet_version > neighbour->subscriber->max_packet_version)
frame->packet_version = neighbour->subscriber->max_packet_version;
if (!dest->unicast){
// make sure we only add broadcast interfaces once
int id = dest->interface - overlay_interfaces;
if (added_interface[id]){
continue;
}
}
if (frame->destination_count < MAX_PACKET_DESTINATIONS)
frame->destinations[frame->destination_count++].destination=add_destination_ref(dest);
}
}
}
return 0;
}
@ -977,6 +1009,7 @@ static struct link_out *create_out_link(struct neighbour *neighbour, overlay_int
else
ret->destination = add_destination_ref(interface->destination);
ret->timeout = gettime_ms()+ret->destination->tick_ms*2;
update_alarm(gettime_ms()+5);
}
return ret;
}

View File

@ -853,7 +853,7 @@ int link_state_legacy_ack(struct overlay_frame *frame, time_ms_t now);
int link_state_ack_soon(struct subscriber *sender);
int link_state_should_forward_broadcast(struct subscriber *transmitter);
int link_unicast_ack(struct subscriber *subscriber, struct overlay_interface *interface, struct sockaddr_in addr);
int link_add_broadcast_destinations(struct overlay_frame *frame);
int link_add_destinations(struct overlay_frame *frame);
int generate_nonce(unsigned char *nonce,int bytes);

View File

@ -145,13 +145,13 @@ test_routing() {
wait_until is_published $SIDC
set_instance +B
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDA:UNICAST :"
assertStdoutGrep --matches=1 "^$SIDA:UNICAST:"
executeOk_servald dna lookup "$DIDC"
assertStdoutLineCount '==' 1
assertStdoutGrep --matches=1 "^sid://$SIDC/local/$DIDC:$DIDC:$NAMEC\$"
set_instance +C
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDA:UNICAST :"
assertStdoutGrep --matches=1 "^$SIDA:UNICAST:"
executeOk_servald dna lookup "$DIDB"
assertStdoutLineCount '==' 1
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"

View File

@ -18,13 +18,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Routing conditions that are known to not be working or covered by tests;
# - No support for multi-hop paths involving any unicast links
# - unicast only links need to be shared in the routing table
# - routing table needs to be shared to unicast only peers
# - unicast IP information should be shared among unicast peers
#
source "${0%/*}/../testframework.sh"
source "${0%/*}/../testdefs.sh"
@ -241,29 +234,33 @@ doc_scan="Network scan with isolated clients"
setup_scan() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
set_instance +B
executeOk_servald config \
set interfaces.1.dummy_address 127.0.1.11
foreach_instance +A +B \
foreach_instance +A +B +C create_single_identity
foreach_instance +A +B +C add_interface 1
foreach_instance +A +B +C \
executeOk_servald config \
set interfaces.1.drop_broadcasts 100
foreach_instance +A +B start_routing_instance
foreach_instance +A +B +C start_routing_instance
}
test_scan() {
set_instance +A
executeOk_servald scan
wait_until scan_completed
wait_until has_seen_instances +B
executeOk_servald mdp ping --timeout=3 $SIDB 1
tfw_cat --stdout --stderr
wait_until --timeout=10 has_seen_instances +B +C
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:UNICAST:"
assertStdoutGrep --matches=1 "^$SIDC:UNICAST:"
executeOk_servald mdp ping --timeout=3 $SIDB 1
tfw_cat --stdout --stderr
set_instance +B
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDA:UNICAST:"
assertStdoutGrep --matches=1 "^$SIDC:INDIRECT:"
executeOk_servald mdp ping --timeout=3 $SIDC 1
tfw_cat --stdout --stderr
}
scan_completed() {
grep "Scan completed" $LOG||return1
grep "Scan completed" $instance_servald_log || return 1
return 0
}
@ -275,7 +272,6 @@ setup_single_filter() {
foreach_instance +A +B add_interface 1
set_instance +B
executeOk_servald config \
set interfaces.1.dummy_address 127.0.1.11 \
set interfaces.1.drop_broadcasts 100
foreach_instance +A +B start_routing_instance
}
@ -360,6 +356,31 @@ test_multihop_linear() {
assertStdoutGrep --matches=1 "^6:$SIDA\$"
}
doc_unicast_route="Route across unicast links"
setup_unicast_route() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C +D create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +B +C add_interface 2
foreach_instance +C +D add_interface 3
set_instance +A
executeOk_servald config \
set interfaces.1.drop_broadcasts 100
set_instance +C
executeOk_servald config \
set interfaces.2.drop_broadcasts 100 \
set interfaces.3.drop_broadcasts 100
foreach_instance +A +B +C +D start_routing_instance
}
test_unicast_route() {
wait_until --timeout=20 path_exists +A +B +C +D
wait_until --timeout=5 path_exists +D +C +B +A
set_instance +A
executeOk_servald mdp ping --timeout=3 $SIDD 1
tfw_cat --stdout --stderr
}
setup_offline() {
setup_servald
assert_no_servald_processes
@ -640,10 +661,10 @@ test_crowded_mess() {
foreach_instance +A +H \
wait_until has_seen_instances +A +H
set_instance +A
executeOk_servald mdp ping --timeout=3 $SIDH 1
tfw_cat --stdout --stderr
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDH:INDIRECT:"
executeOk_servald mdp ping --timeout=3 $SIDH 1
tfw_cat --stdout --stderr
}
runTests "$@"