Specify that unicast traffic should use unicast UDP packets

This commit is contained in:
Jeremy Lakeman 2013-01-29 11:57:13 +11:00
parent 88f7fef992
commit b35c1aca43
9 changed files with 100 additions and 24 deletions

View File

@ -334,13 +334,15 @@ ATOM(struct pattern_list, match, PATTERN_LIST_EMPTY, cf_opt_pattern_list,
STRING(256, dummy, "", cf_opt_str_nonempty,, "Path of dummy file, absolute or relative to server.dummy_interface_dir") STRING(256, dummy, "", cf_opt_str_nonempty,, "Path of dummy file, absolute or relative to server.dummy_interface_dir")
ATOM(struct in_addr, dummy_address, (struct in_addr){htonl(0x7F000001)}, cf_opt_in_addr,, "Dummy interface address") ATOM(struct in_addr, dummy_address, (struct in_addr){htonl(0x7F000001)}, cf_opt_in_addr,, "Dummy interface address")
ATOM(struct in_addr, dummy_netmask, (struct in_addr){htonl(0xFFFFFF00)}, cf_opt_in_addr,, "Dummy interface netmask") ATOM(struct in_addr, dummy_netmask, (struct in_addr){htonl(0xFFFFFF00)}, cf_opt_in_addr,, "Dummy interface netmask")
ATOM(int, dummy_filter_broadcasts, 0, cf_opt_int_boolean,, "If true, drop all incoming broadcast packets") ATOM(char, dummy_filter_broadcasts, 0, cf_opt_char_boolean,, "If true, drop all incoming broadcast packets")
ATOM(char, dummy_filter_unicasts, 0, cf_opt_char_boolean,, "If true, drop all incoming unicast packets")
ATOM(short, type, OVERLAY_INTERFACE_WIFI, cf_opt_interface_type,, "Type of network interface") ATOM(short, type, OVERLAY_INTERFACE_WIFI, cf_opt_interface_type,, "Type of network interface")
ATOM(uint16_t, port, RHIZOME_HTTP_PORT, cf_opt_uint16_nonzero,, "Port number for network interface") ATOM(uint16_t, port, RHIZOME_HTTP_PORT, cf_opt_uint16_nonzero,, "Port number for network interface")
ATOM(int, packet_interval, -1, cf_opt_int,, "Minimum interval between packets in microseconds") ATOM(int, packet_interval, -1, cf_opt_int,, "Minimum interval between packets in microseconds")
ATOM(int, mdp_tick_ms, -1, cf_opt_int32_nonneg,, "Override MDP tick interval for this interface") ATOM(int, mdp_tick_ms, -1, cf_opt_int32_nonneg,, "Override MDP tick interval for this interface")
ATOM(char, send_broadcasts, 1, cf_opt_char_boolean,, "If false, don't send any broadcast packets") ATOM(char, send_broadcasts, 1, cf_opt_char_boolean,, "If false, don't send any broadcast packets")
ATOM(int, default_route, 0, cf_opt_int_boolean,, "If true, use this interface as a default route") ATOM(char, default_route, 0, cf_opt_char_boolean,, "If true, use this interface as a default route")
ATOM(char, prefer_unicast, 0, cf_opt_char_boolean,, "If true, send unicast data as unicast IP packets if available")
END_STRUCT END_STRUCT
ARRAY(interface_list, SORTED NO_DUPLICATES) ARRAY(interface_list, SORTED NO_DUPLICATES)

View File

@ -72,6 +72,7 @@ struct subscriber{
struct sockaddr_in address; struct sockaddr_in address;
time_ms_t last_stun_request; time_ms_t last_stun_request;
time_ms_t last_probe; time_ms_t last_probe;
time_ms_t last_probe_response;
time_ms_t last_rx; time_ms_t last_rx;
time_ms_t last_acked; time_ms_t last_acked;
time_ms_t last_tx; time_ms_t last_tx;

View File

@ -397,6 +397,8 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr
return WHYF("Invalid tick interval %d specified for interface %s", interface->tick_ms, name); return WHYF("Invalid tick interval %d specified for interface %s", interface->tick_ms, name);
limit_init(&interface->transfer_limit, packet_interval); limit_init(&interface->transfer_limit, packet_interval);
interface->prefer_unicast = ifconfig->prefer_unicast;
if (ifconfig->dummy[0]) { if (ifconfig->dummy[0]) {
interface->fileP = 1; interface->fileP = 1;
@ -421,6 +423,7 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr
interface->broadcast_address.sin_port = htons(PORT_DNA); interface->broadcast_address.sin_port = htons(PORT_DNA);
interface->broadcast_address.sin_addr.s_addr = interface->address.sin_addr.s_addr | ~interface->netmask.s_addr; interface->broadcast_address.sin_addr.s_addr = interface->address.sin_addr.s_addr | ~interface->netmask.s_addr;
interface->drop_broadcasts = ifconfig->dummy_filter_broadcasts; interface->drop_broadcasts = ifconfig->dummy_filter_broadcasts;
interface->drop_unicasts = ifconfig->dummy_filter_unicasts;
/* Seek to end of file as initial reading point */ /* Seek to end of file as initial reading point */
interface->recv_offset = lseek(interface->alarm.poll.fd,0,SEEK_END); interface->recv_offset = lseek(interface->alarm.poll.fd,0,SEEK_END);
@ -586,7 +589,7 @@ void overlay_dummy_poll(struct sched_ent *alarm)
if (config.debug.packetrx) if (config.debug.packetrx)
DEBUG_packet_visualise("Read from dummy interface", packet.payload, packet.payload_length); DEBUG_packet_visualise("Read from dummy interface", packet.payload, packet.payload_length);
if (memcmp(&packet.dst_addr, &interface->address, sizeof(packet.dst_addr))==0 || if (((!interface->drop_unicasts) && memcmp(&packet.dst_addr, &interface->address, sizeof(packet.dst_addr))==0) ||
((!interface->drop_broadcasts) && ((!interface->drop_broadcasts) &&
memcmp(&packet.dst_addr, &interface->broadcast_address, sizeof(packet.dst_addr))==0)){ memcmp(&packet.dst_addr, &interface->broadcast_address, sizeof(packet.dst_addr))==0)){

View File

@ -225,18 +225,20 @@ overlay_mdp_service_probe(overlay_mdp_frame *mdp)
} }
struct subscriber *peer = find_subscriber(mdp->out.src.sid, SID_SIZE, 0); struct subscriber *peer = find_subscriber(mdp->out.src.sid, SID_SIZE, 0);
if (peer->reachable == REACHABLE_SELF)
RETURN(0);
struct probe_contents probe; struct probe_contents probe;
bcopy(&mdp->out.payload, &probe, sizeof(struct probe_contents)); bcopy(&mdp->out.payload, &probe, sizeof(struct probe_contents));
if (probe.addr.sin_family!=AF_INET) if (probe.addr.sin_family!=AF_INET)
RETURN(WHY("Unsupported address family")); RETURN(WHY("Unsupported address family"));
if (peer->reachable == REACHABLE_NONE || peer->reachable == REACHABLE_INDIRECT || (peer->reachable & REACHABLE_ASSUMED)){ peer->last_probe_response = gettime_ms();
peer->interface = &overlay_interfaces[probe.interface]; peer->interface = &overlay_interfaces[probe.interface];
peer->address.sin_family = AF_INET; peer->address.sin_family = AF_INET;
peer->address.sin_addr = probe.addr.sin_addr; peer->address.sin_addr = probe.addr.sin_addr;
peer->address.sin_port = probe.addr.sin_port; peer->address.sin_port = probe.addr.sin_port;
set_reachable(peer, REACHABLE_UNICAST); set_reachable(peer, REACHABLE_UNICAST | (peer->reachable & REACHABLE_DIRECT));
}
RETURN(0); RETURN(0);
} }

View File

@ -235,23 +235,24 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
// TODO probe unicast links when we detect an address change. // TODO probe unicast links when we detect an address change.
// always update the IP address we heard them from, even if we don't need to use it right now
context.sender->address = f.recvaddr;
// if this is a dummy announcement for a node that isn't in our routing table // if this is a dummy announcement for a node that isn't in our routing table
if (context.sender->reachable == REACHABLE_NONE) { if (context.sender->reachable == REACHABLE_NONE) {
context.sender->interface = interface; context.sender->interface = interface;
context.sender->address = f.recvaddr;
context.sender->last_probe = 0;
// assume for the moment, that we can reply with the same packet type // assume for the moment, that we can reply with the same packet type
if (packet_flags&PACKET_UNICAST){ if (packet_flags&PACKET_UNICAST){
/* Note the probe payload must be queued before any SID/SAS request so we can force the packet to have a full sid */
overlay_send_probe(context.sender, f.recvaddr, interface, OQ_MESH_MANAGEMENT);
set_reachable(context.sender, REACHABLE_UNICAST|REACHABLE_ASSUMED); set_reachable(context.sender, REACHABLE_UNICAST|REACHABLE_ASSUMED);
}else{ }else{
set_reachable(context.sender, REACHABLE_BROADCAST|REACHABLE_ASSUMED); set_reachable(context.sender, REACHABLE_BROADCAST|REACHABLE_ASSUMED);
} }
} }
/* Note the probe payload must be queued before any SID/SAS request so we can force the packet to have a full sid */
if (context.sender->last_probe==0 || now - context.sender->last_probe > 5000)
overlay_send_probe(context.sender, f.recvaddr, interface, OQ_MESH_MANAGEMENT);
if ((!(packet_flags&PACKET_UNICAST)) && context.sender->last_acked + interface->tick_ms <= now){ if ((!(packet_flags&PACKET_UNICAST)) && context.sender->last_acked + interface->tick_ms <= now){
overlay_route_ack_selfannounce(interface, overlay_route_ack_selfannounce(interface,
context.sender->last_acked>now - 3*interface->tick_ms?context.sender->last_acked:now, context.sender->last_acked>now - 3*interface->tick_ms?context.sender->last_acked:now,
@ -259,6 +260,7 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
context.sender->last_acked = now; context.sender->last_acked = now;
} }
} }
if (packet_flags & PACKET_UNICAST) if (packet_flags & PACKET_UNICAST)

View File

@ -165,6 +165,10 @@ int overlay_payload_enqueue(struct overlay_frame *p)
if (p->queue>=OQ_MAX) if (p->queue>=OQ_MAX)
return WHY("Invalid queue specified"); return WHY("Invalid queue specified");
/* queue a unicast probe if we haven't for a while. */
if (p->destination && (p->destination->last_probe==0 || gettime_ms() - p->destination->last_probe > 5000))
overlay_send_probe(p->destination, p->destination->address, p->destination->interface, OQ_MESH_MANAGEMENT);
overlay_txqueue *queue = &overlay_tx[p->queue]; overlay_txqueue *queue = &overlay_tx[p->queue];
if (config.debug.packettx) if (config.debug.packettx)
@ -346,6 +350,17 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
frame->interface = frame->next_hop->interface; frame->interface = frame->next_hop->interface;
// if both broadcast and unicast are available, pick on based on interface preference
if ((r&(REACHABLE_UNICAST|REACHABLE_BROADCAST))==(REACHABLE_UNICAST|REACHABLE_BROADCAST)){
if (frame->interface->prefer_unicast){
r=REACHABLE_UNICAST;
// used by tests
if (config.debug.overlayframes)
DEBUGF("Choosing to send via unicast for %s", alloca_tohex_sid(frame->destination->sid));
}else
r=REACHABLE_BROADCAST;
}
if(r&REACHABLE_UNICAST){ if(r&REACHABLE_UNICAST){
frame->recvaddr = frame->next_hop->address; frame->recvaddr = frame->next_hop->address;
frame->unicast = 1; frame->unicast = 1;

View File

@ -411,6 +411,9 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
best_observation=-1; best_observation=-1;
reachable=REACHABLE_BROADCAST; reachable=REACHABLE_BROADCAST;
interface = &overlay_interfaces[i]; interface = &overlay_interfaces[i];
// if we've probed this unicast link, preserve the status
if ((n->subscriber->reachable&REACHABLE_UNICAST) && !(n->subscriber->reachable&REACHABLE_ASSUMED))
reachable|=REACHABLE_UNICAST;
} }
} }
} }
@ -455,6 +458,7 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
n->subscriber->next_hop = next_hop; n->subscriber->next_hop = next_hop;
break; break;
case REACHABLE_BROADCAST: case REACHABLE_BROADCAST:
case REACHABLE_BROADCAST|REACHABLE_UNICAST:
n->subscriber->interface = interface; n->subscriber->interface = interface;
break; break;
} }

View File

@ -354,7 +354,8 @@ typedef struct overlay_interface {
char name[256]; char name[256];
int recv_offset; int recv_offset;
int fileP; // dummyP int fileP; // dummyP
int drop_broadcasts; char drop_broadcasts;
char drop_unicasts;
int port; int port;
int type; int type;
/* Number of milli-seconds per tick for this interface, which is basically related to the /* Number of milli-seconds per tick for this interface, which is basically related to the
@ -371,11 +372,11 @@ typedef struct overlay_interface {
unsigned tick_ms; /* milliseconds per tick */ unsigned tick_ms; /* milliseconds per tick */
struct subscriber *next_advert; struct subscriber *next_advert;
int send_broadcasts; char send_broadcasts;
char prefer_unicast;
/* The time of the last tick on this interface in milli seconds */ /* The time of the last tick on this interface in milli seconds */
time_ms_t last_tick_ms; time_ms_t last_tick_ms;
/* How many times have we abbreviated our address since we last announced it in full? */
int ticks_since_sent_full_address;
/* sequence number of last packet sent on this interface. /* sequence number of last packet sent on this interface.
Used to allow NACKs that can request retransmission of recent packets. Used to allow NACKs that can request retransmission of recent packets.

View File

@ -75,7 +75,7 @@ test_single_link() {
executeOk_servald mdp ping $SIDB 1 executeOk_servald mdp ping $SIDB 1
tfw_cat --stdout --stderr tfw_cat --stdout --stderr
executeOk_servald route print executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:BROADCAST :" assertStdoutGrep --matches=1 "^$SIDB:BROADCAST UNICAST :"
} }
setup_multiple_nodes() { setup_multiple_nodes() {
@ -98,9 +98,9 @@ test_multiple_nodes() {
executeOk_servald mdp ping $SIDD 1 executeOk_servald mdp ping $SIDD 1
tfw_cat --stdout --stderr tfw_cat --stdout --stderr
executeOk_servald route print executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:BROADCAST :" assertStdoutGrep --matches=1 "^$SIDB:BROADCAST "
assertStdoutGrep --matches=1 "^$SIDC:BROADCAST :" assertStdoutGrep --matches=1 "^$SIDC:BROADCAST "
assertStdoutGrep --matches=1 "^$SIDD:BROADCAST :" assertStdoutGrep --matches=1 "^$SIDD:BROADCAST "
} }
setup_scan() { setup_scan() {
@ -134,6 +134,52 @@ test_scan() {
assertStdoutGrep --matches=1 "^$SIDB:UNICAST :" assertStdoutGrep --matches=1 "^$SIDB:UNICAST :"
} }
setup_broadcast_only() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B \
executeOk_servald config \
set interfaces.1.dummy_filter_unicasts 1
foreach_instance +A +B start_routing_instance
}
doc_broadcast_only="Broadcast packets only"
test_broadcast_only() {
foreach_instance +A +B \
wait_until has_seen_instances +A +B
set_instance +A
executeOk_servald mdp ping $SIDB 1
tfw_cat --stdout --stderr
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:BROADCAST :"
}
setup_prefer_unicast() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B \
executeOk_servald config \
set interfaces.1.prefer_unicast 1 \
set debug.overlayframes 1
foreach_instance +A +B start_routing_instance
}
doc_prefer_unicast="Prefer unicast packets"
test_prefer_unicast() {
foreach_instance +A +B \
wait_until has_seen_instances +A +B
set_instance +A
executeOk_servald mdp ping $SIDB 1
tfw_cat --stdout --stderr
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:BROADCAST UNICAST :"
assertGrep "$instance_servald_log" 'Choosing to send via unicast'
}
setup_multihop_linear() { setup_multihop_linear() {
setup_servald setup_servald
assert_no_servald_processes assert_no_servald_processes
@ -152,7 +198,7 @@ test_multihop_linear() {
executeOk_servald mdp ping $SIDD 1 executeOk_servald mdp ping $SIDD 1
tfw_cat --stdout --stderr tfw_cat --stdout --stderr
executeOk_servald route print executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:BROADCAST :" assertStdoutGrep --matches=1 "^$SIDB:BROADCAST UNICAST :"
assertStdoutGrep --matches=1 "^$SIDC:INDIRECT :" assertStdoutGrep --matches=1 "^$SIDC:INDIRECT :"
assertStdoutGrep --matches=1 "^$SIDD:INDIRECT :" assertStdoutGrep --matches=1 "^$SIDD:INDIRECT :"
} }