Rewrote parts of the retransmission logic so that collect is robust against the situation where the MAC layer will fail to callback after a packet has been transmitted.

This commit is contained in:
adamdunkels 2010-10-24 21:08:19 +00:00
parent 8fa7bf6c31
commit 77ecfb0366
1 changed files with 92 additions and 49 deletions

View File

@ -33,7 +33,7 @@
* *
* This file is part of the Contiki operating system. * This file is part of the Contiki operating system.
* *
* $Id: collect.c,v 1.62 2010/10/19 07:34:29 adamdunkels Exp $ * $Id: collect.c,v 1.63 2010/10/24 21:08:19 adamdunkels Exp $
*/ */
/** /**
@ -125,11 +125,11 @@ struct ack_msg {
specifies the maximum length of the output queue. If the queue is specifies the maximum length of the output queue. If the queue is
full, incoming packets are dropped instead of being forwarded. */ full, incoming packets are dropped instead of being forwarded. */
#define MAX_MAC_REXMITS 2 #define MAX_MAC_REXMITS 2
#define MAX_ACK_MAC_REXMITS 3 #define MAX_ACK_MAC_REXMITS 7
#define REXMIT_TIME CLOCK_SECOND * 1 #define REXMIT_TIME CLOCK_SECOND * 6
#define MAX_REXMIT_TIME_SCALING 2 #define MAX_REXMIT_TIME_SCALING 0
#define FORWARD_PACKET_LIFETIME_BASE (4 * (REXMIT_TIME)) #define FORWARD_PACKET_LIFETIME_BASE REXMIT_TIME
#define MAX_SENDING_QUEUE QUEUEBUF_NUM / 2 #define MAX_SENDING_QUEUE 3 * QUEUEBUF_NUM / 4
#define KEEPALIVE_REXMITS 8 #define KEEPALIVE_REXMITS 8
#define MAX_REXMITS 31 #define MAX_REXMITS 31
@ -158,8 +158,8 @@ MEMB(send_queue_memb, struct packetqueue_item, MAX_SENDING_QUEUE);
queue, the system periodically sends a dummy packet to potential queue, the system periodically sends a dummy packet to potential
parents, i.e., neighbors with a lower rtmetric than we have but for parents, i.e., neighbors with a lower rtmetric than we have but for
which we do not yet have a link quality estimate. */ which we do not yet have a link quality estimate. */
#define PROACTIVE_MAINTENANCE_INTERVAL CLOCK_SECOND * 60 #define PROACTIVE_MAINTENANCE_INTERVAL CLOCK_SECOND * 30
#define PROACTIVE_MAINTENANCE_REXMITS 8 #define PROACTIVE_MAINTENANCE_REXMITS 15
/* COLLECT_CONF_ANNOUNCEMENTS defines if the Collect implementation /* COLLECT_CONF_ANNOUNCEMENTS defines if the Collect implementation
should use Contiki's announcement primitive to announce its routes should use Contiki's announcement primitive to announce its routes
@ -203,7 +203,6 @@ struct {
/* Debug definition: draw routing tree in Cooja. */ /* Debug definition: draw routing tree in Cooja. */
#define DRAW_TREE 0 #define DRAW_TREE 0
#define DEBUG 0 #define DEBUG 0
#if DEBUG #if DEBUG
#include <stdio.h> #include <stdio.h>
@ -215,6 +214,7 @@ struct {
/* Forward declarations. */ /* Forward declarations. */
static void send_queued_packet(struct collect_conn *c); static void send_queued_packet(struct collect_conn *c);
static void retransmit_callback(void *ptr); static void retransmit_callback(void *ptr);
static void retransmit_not_sent_callback(void *ptr);
static void set_keepalive_timer(struct collect_conn *c); static void set_keepalive_timer(struct collect_conn *c);
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -319,9 +319,11 @@ update_parent(struct collect_conn *tc)
stats.foundroute++; stats.foundroute++;
bump_advertisement(tc); bump_advertisement(tc);
} else { } else {
// printf("#A e=%d\n", collect_neighbor_link_estimate(best));
if(collect_neighbor_rtmetric_link_estimate(best) + if(collect_neighbor_rtmetric_link_estimate(best) +
SIGNIFICANT_RTMETRIC_PARENT_CHANGE < SIGNIFICANT_RTMETRIC_PARENT_CHANGE <
collect_neighbor_rtmetric_link_estimate(current)) { collect_neighbor_rtmetric_link_estimate(current)) {
/* We switch parent. */ /* We switch parent. */
PRINTF("update_parent: new parent %d.%d (%d) old parent %d.%d (%d)\n", PRINTF("update_parent: new parent %d.%d (%d) old parent %d.%d (%d)\n",
best->addr.u8[0], best->addr.u8[1], best->addr.u8[0], best->addr.u8[1],
@ -332,8 +334,6 @@ update_parent(struct collect_conn *tc)
stats.newparent++; stats.newparent++;
/* Since we now have a significantly better or worse rtmetric than /* Since we now have a significantly better or worse rtmetric than
we had before, we let our neighbors know this quickly. */ we had before, we let our neighbors know this quickly. */
PRINTF("update_rtmetric: new_rtmetric %d + %d < old_rtmetric %d\n",
new_rtmetric, SIGNIFICANT_RTMETRIC_PARENT_CHANGE, old_rtmetric);
bump_advertisement(tc); bump_advertisement(tc);
if(DRAW_TREE) { if(DRAW_TREE) {
@ -481,6 +481,27 @@ enqueue_dummy_packet(struct collect_conn *c, int rexmits)
return 0; return 0;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void
send_packet(struct collect_conn *c, struct collect_neighbor *n)
{
clock_time_t time;
uint8_t rexmit_time_scaling;
unicast_send(&c->unicast_conn, &n->addr);
/* Compute the retransmission timeout and set up the
retransmission timer. */
rexmit_time_scaling = c->transmissions / (MAX_MAC_REXMITS + 1);
/* if(rexmit_time_scaling > MAX_REXMIT_TIME_SCALING) {
rexmit_time_scaling = MAX_REXMIT_TIME_SCALING;
}
time = REXMIT_TIME << rexmit_time_scaling;
time = 3 * time / 2 + (random_rand() % (time / 4));*/
time = 3 * REXMIT_TIME / 4 + (random_rand() % (REXMIT_TIME / 4));
// printf("retransmission time %lu scaling %d\n", time, rexmit_time_scaling);
ctimer_set(&c->retransmission_timer, time,
retransmit_not_sent_callback, c);
}
/*---------------------------------------------------------------------------*/
/** /**
* This function is called when a queued packet should be sent * This function is called when a queued packet should be sent
* out. The function takes the first packet on the output queue, adds * out. The function takes the first packet on the output queue, adds
@ -517,7 +538,8 @@ send_queued_packet(struct collect_conn *c)
link estimate and send a dummy packet to it. This allows us to link estimate and send a dummy packet to it. This allows us to
quickly gauge the link quality of neighbors that we do not quickly gauge the link quality of neighbors that we do not
currently use as parents. */ currently use as parents. */
if(timer_expired(&c->proactive_maintenence_timer)) { if(c->rtmetric != RTMETRIC_SINK &&
timer_expired(&c->proactive_maintenence_timer)) {
struct collect_neighbor *n; struct collect_neighbor *n;
timer_set(&c->proactive_maintenence_timer, timer_set(&c->proactive_maintenence_timer,
@ -602,7 +624,7 @@ send_queued_packet(struct collect_conn *c)
memcpy(packetbuf_dataptr(), &hdr, sizeof(struct data_msg_hdr)); memcpy(packetbuf_dataptr(), &hdr, sizeof(struct data_msg_hdr));
/* Send the packet. */ /* Send the packet. */
unicast_send(&c->unicast_conn, &n->addr); send_packet(c, n);
} else { } else {
#if COLLECT_ANNOUNCEMENTS #if COLLECT_ANNOUNCEMENTS
@ -701,8 +723,7 @@ retransmit_current_packet(struct collect_conn *c)
memcpy(packetbuf_dataptr(), &hdr, sizeof(struct data_msg_hdr)); memcpy(packetbuf_dataptr(), &hdr, sizeof(struct data_msg_hdr));
/* Send the packet. */ /* Send the packet. */
unicast_send(&c->unicast_conn, &n->addr); send_packet(c, n);
} }
} }
@ -974,6 +995,7 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from)
ackflags |= ACK_FLAGS_RTMETRIC_NEEDS_UPDATE; ackflags |= ACK_FLAGS_RTMETRIC_NEEDS_UPDATE;
} }
printf("potential loop detected\n");
packetbuf_set_attr(PACKETBUF_ATTR_HOPS, packetbuf_set_attr(PACKETBUF_ATTR_HOPS,
packetbuf_attr(PACKETBUF_ATTR_HOPS) + 1); packetbuf_attr(PACKETBUF_ATTR_HOPS) + 1);
packetbuf_set_attr(PACKETBUF_ATTR_TTL, packetbuf_set_attr(PACKETBUF_ATTR_TTL,
@ -1032,40 +1054,6 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
node_packet_sent(struct unicast_conn *c, int status, int transmissions)
{
struct collect_conn *tc = (struct collect_conn *)
((char *)c - offsetof(struct collect_conn, unicast_conn));
clock_time_t time;
uint8_t rexmit_time_scaling;
/* For data packets, we record the number of transmissions */
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
PACKETBUF_ATTR_PACKET_TYPE_DATA) {
tc->transmissions += transmissions;
PRINTF("%d.%d: MAC sent %d transmissions to %d.%d, status %d, total transmissions %d\n",
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
transmissions,
tc->current_parent.u8[0], tc->current_parent.u8[1],
status, tc->transmissions);
/* Compute the retransmission timeout and set up the
retransmission timer. */
rexmit_time_scaling = tc->transmissions / (MAX_MAC_REXMITS + 1);
if(rexmit_time_scaling > MAX_REXMIT_TIME_SCALING) {
rexmit_time_scaling = MAX_REXMIT_TIME_SCALING;
}
time = REXMIT_TIME << rexmit_time_scaling;
time = time / 2 + (random_rand() % (time / 2));
PRINTF("retransmission time %lu scaling %d\n", time, rexmit_time_scaling);
ctimer_set(&tc->retransmission_timer, time,
retransmit_callback, tc);
}
}
/*---------------------------------------------------------------------------*/
static void
timedout(struct collect_conn *tc) timedout(struct collect_conn *tc)
{ {
struct collect_neighbor *n; struct collect_neighbor *n;
@ -1085,6 +1073,53 @@ timedout(struct collect_conn *tc)
set_keepalive_timer(tc); set_keepalive_timer(tc);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void
node_packet_sent(struct unicast_conn *c, int status, int transmissions)
{
struct collect_conn *tc = (struct collect_conn *)
((char *)c - offsetof(struct collect_conn, unicast_conn));
/* For data packets, we record the number of transmissions */
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
PACKETBUF_ATTR_PACKET_TYPE_DATA) {
tc->transmissions += transmissions;
// printf("tx %d\n", tc->transmissions);
PRINTF("%d.%d: MAC sent %d transmissions to %d.%d, status %d, total transmissions %d\n",
rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
transmissions,
tc->current_parent.u8[0], tc->current_parent.u8[1],
status, tc->transmissions);
if(tc->transmissions >= tc->max_rexmits) {
timedout(tc);
stats.timedout++;
} else {
clock_time_t time = (random_rand() % (REXMIT_TIME / 4));
// printf("retransmission time %lu scaling %d\n", time, rexmit_time_scaling);
ctimer_set(&tc->retransmission_timer, time,
retransmit_callback, tc);
}
}
}
/*---------------------------------------------------------------------------*/
/**
* This function is called from a ctimer that is setup when a packet
* is first transmitted. If the MAC layer signals that the packet is
* sent, the ctimer will be stopped before this function is called. If
* this function ends up being called, we add the maximum number of
* MAC layer transmissions to the transmission count, and call the
* retransmit function.
*/
static void
retransmit_not_sent_callback(void *ptr)
{
struct collect_conn *c = ptr;
PRINTF("retransmit not sent, %d transmissions\n", c->transmissions);
c->transmissions += MAX_MAC_REXMITS + 1;
retransmit_callback(c);
}
/*---------------------------------------------------------------------------*/
/** /**
* This function is called from a ctimer that is setup when a packet * This function is called from a ctimer that is setup when a packet
* is sent. The purpose of this function is to either retransmit the * is sent. The purpose of this function is to either retransmit the
@ -1296,6 +1331,14 @@ collect_set_sink(struct collect_conn *tc, int should_be_sink)
tc->rtmetric = RTMETRIC_SINK; tc->rtmetric = RTMETRIC_SINK;
PRINTF("collect_set_sink: tc->rtmetric %d\n", tc->rtmetric); PRINTF("collect_set_sink: tc->rtmetric %d\n", tc->rtmetric);
bump_advertisement(tc); bump_advertisement(tc);
/* Purge the outgoing packet queue. */
while(packetqueue_len(&tc->send_queue) > 0) {
packetqueue_dequeue(&tc->send_queue);
}
/* Stop the retransmission timer. */
ctimer_stop(&tc->retransmission_timer);
} else { } else {
tc->rtmetric = RTMETRIC_MAX; tc->rtmetric = RTMETRIC_MAX;
} }