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:
parent
8fa7bf6c31
commit
77ecfb0366
1 changed files with 92 additions and 49 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue