From 605392522f3d691b2f5a4069d46a86370ccf662a Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Sun, 3 Oct 2010 20:08:44 +0000 Subject: [PATCH] Bugfixes and improvements: rtmetrics are now 16-bit clean. Added experimental feature that proactively probes neighbors that have not yet been tried out, in order to get an initial ETX for them. --- core/net/rime/collect.c | 216 +++++++++++++++++++++++++++------------- core/net/rime/collect.h | 8 +- 2 files changed, 154 insertions(+), 70 deletions(-) diff --git a/core/net/rime/collect.c b/core/net/rime/collect.c index 8ef550b31..98015cd83 100644 --- a/core/net/rime/collect.c +++ b/core/net/rime/collect.c @@ -33,7 +33,7 @@ * * This file is part of the Contiki operating system. * - * $Id: collect.c,v 1.54 2010/09/28 06:53:02 adamdunkels Exp $ + * $Id: collect.c,v 1.55 2010/10/03 20:08:44 adamdunkels Exp $ */ /** @@ -127,9 +127,9 @@ struct ack_msg { #define MAX_MAC_REXMITS 2 #define MAX_ACK_MAC_REXMITS 3 #define REXMIT_TIME CLOCK_SECOND * 1 -#define FORWARD_PACKET_LIFETIME (6 * (REXMIT_TIME) << 3) +#define FORWARD_PACKET_LIFETIME (60 * (REXMIT_TIME) << 3) #define MAX_SENDING_QUEUE 16 -#define KEEPALIVE_REXMITS 4 +#define KEEPALIVE_REXMITS 8 MEMB(send_queue_memb, struct packetqueue_item, MAX_SENDING_QUEUE); @@ -144,14 +144,22 @@ MEMB(send_queue_memb, struct packetqueue_item, MAX_SENDING_QUEUE); rtmetric. This is used to determine when a new parent should be chosen over an old parent and when to begin more rapidly advertise a new rtmetric. */ -#define SIGNIFICANT_RTMETRIC_CHANGE (COLLECT_LINK_ESTIMATE_UNIT + \ - COLLECT_LINK_ESTIMATE_UNIT / 2) +#define SIGNIFICANT_RTMETRIC_PARENT_CHANGE (COLLECT_LINK_ESTIMATE_UNIT + \ + COLLECT_LINK_ESTIMATE_UNIT / 2) /* This defines the maximum hops that a packet can take before it is dropped. */ #define MAX_HOPLIM 15 +/* Experimental mechanism: when there are no packets in the send + queue, the system periodically sends a dummy packet to potential + parents, i.e., neighbors with a lower rtmetric than we have but for + which we do not yet have a link quality estimate. */ +#define WITH_PROACTIVE_MAINTENANCE 0 +#define PROACTIVE_MAINTENANCE_INTERVAL CLOCK_SECOND * 60 * 4 +#define PROACTIVE_MAINTENANCE_REXMITS 8 + /* COLLECT_CONF_ANNOUNCEMENTS defines if the Collect implementation should use Contiki's announcement primitive to announce its routes or if it should use periodic broadcasts. */ @@ -215,11 +223,11 @@ static void set_keepalive_timer(struct collect_conn *c); * parent. * */ -static uint8_t +static uint16_t rtmetric_compute(struct collect_conn *tc) { struct collect_neighbor *n; - uint8_t rtmetric = RTMETRIC_MAX; + uint16_t rtmetric = RTMETRIC_MAX; /* This function computes the current rtmetric for this node. It uses the rtmetric of the parent node in the tree and adds the @@ -291,7 +299,8 @@ update_parent(struct collect_conn *tc) #if DRAW_TREE printf("#L %d 0\n", tc->parent.u8[0]); #endif /* DRAW_TREE */ - if(collect_neighbor_rtmetric_link_estimate(best) + SIGNIFICANT_RTMETRIC_CHANGE < + if(collect_neighbor_rtmetric_link_estimate(best) + + SIGNIFICANT_RTMETRIC_PARENT_CHANGE < collect_neighbor_rtmetric_link_estimate(current)) { /* We switch parent. */ PRINTF("update_parent: new parent %d.%d (%d) old parent %d.%d (%d)\n", @@ -348,7 +357,7 @@ update_rtmetric(struct collect_conn *tc) /* We should only update the rtmetric if we are not the sink. */ if(tc->rtmetric != RTMETRIC_SINK) { - uint8_t old_rtmetric, new_rtmetric; + uint16_t old_rtmetric, new_rtmetric; /* We remember the current (old) rtmetric for later. */ old_rtmetric = tc->rtmetric; @@ -385,10 +394,10 @@ update_rtmetric(struct collect_conn *tc) /* If we now have a significantly better or worse rtmetric than we had before, what we need to make sure that our neighbors find out about this quickly. */ - if(new_rtmetric < old_rtmetric - SIGNIFICANT_RTMETRIC_CHANGE || - new_rtmetric > old_rtmetric + SIGNIFICANT_RTMETRIC_CHANGE) { + if(new_rtmetric < old_rtmetric - SIGNIFICANT_RTMETRIC_PARENT_CHANGE || + new_rtmetric > old_rtmetric + SIGNIFICANT_RTMETRIC_PARENT_CHANGE) { PRINTF("update_rtmetric: new_rtmetric %d + %d < old_rtmetric %d\n", - new_rtmetric, SIGNIFICANT_RTMETRIC_CHANGE, old_rtmetric); + new_rtmetric, SIGNIFICANT_RTMETRIC_PARENT_CHANGE, old_rtmetric); bump_advertisement(tc); } } @@ -409,6 +418,36 @@ update_rtmetric(struct collect_conn *tc) #endif /* DRAW_TREE */ } /*---------------------------------------------------------------------------*/ +static int +enqueue_dummy_packet(struct collect_conn *c, int rexmits) +{ + struct collect_neighbor *n; + + packetbuf_clear(); + packetbuf_set_attr(PACKETBUF_ATTR_EPACKET_ID, c->eseqno - 1); + packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, c->seqno - 1); + packetbuf_set_addr(PACKETBUF_ADDR_ESENDER, &rimeaddr_node_addr); + packetbuf_set_attr(PACKETBUF_ATTR_HOPS, 1); + packetbuf_set_attr(PACKETBUF_ATTR_TTL, 1); + packetbuf_set_attr(PACKETBUF_ATTR_MAX_REXMIT, rexmits); + + PRINTF("%d.%d: enqueueing dummy packet %d, max_rexmits %d\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], + packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID), + packetbuf_attr(PACKETBUF_ATTR_MAX_REXMIT)); + + /* Allocate space for the header. */ + packetbuf_hdralloc(sizeof(struct data_msg_hdr)); + + n = collect_neighbor_list_find(&c->neighbor_list, &c->parent); + if(n != NULL) { + return packetqueue_enqueue_packetbuf(&c->send_queue, + FORWARD_PACKET_LIFETIME, + c); + } + return 0; +} +/*---------------------------------------------------------------------------*/ /** * This function is called when a queued packet should be sent * out. The function takes the first packet on the output queue, adds @@ -425,20 +464,52 @@ send_queued_packet(struct collect_conn *c) struct data_msg_hdr hdr; int max_mac_rexmits; - /* Grab the first packet on the send queue. */ - i = packetqueue_first(&c->send_queue); - if(i == NULL) { - PRINTF("%d.%d: nothing on queue\n", - rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); - /* No packet on the queue, so there is nothing for us to send. */ + /* If we are currently sending a packet, we do not attempt to send + another one. */ + if(c->sending) { + PRINTF("%d.%d: queue, c is sending\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); return; } - if(c->sending) { - /* If we are currently sending a packet, we wait until the - packet is forwarded and try again then. */ - PRINTF("%d.%d: queue, c is sending\n", - rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); + + /* Grab the first packet on the send queue. */ + i = packetqueue_first(&c->send_queue); + if(i == NULL) { + PRINTF("%d.%d: nothing on queue\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); + /* No packet on the queue, so there is nothing for us to send. */ + + /* XXX experimental feature: go through the list of neighbors to + find a potential parent for which we do not have a link + estimate and send a dummy packet to it. This allows us to + quickly gauge the link quality of neighbors that we do not + currently use as parents. */ + if(WITH_PROACTIVE_MAINTENANCE && timer_expired(&c->proactive_maintenence_timer)) { + struct collect_neighbor *n; + + timer_set(&c->proactive_maintenence_timer, + PROACTIVE_MAINTENANCE_INTERVAL); + + for(n = list_head(collect_neighbor_list(&c->neighbor_list)); + n != NULL; n = list_item_next(n)) { + if(n->rtmetric + COLLECT_LINK_ESTIMATE_UNIT < c->rtmetric && + collect_link_estimate_num_estimates(&n->le) == 0) { + rimeaddr_t current_parent; + + printf("proactive maintenance: found neighbor with no link estimate, %d.%d\n", + n->addr.u8[0], n->addr.u8[1]); + + rimeaddr_copy(¤t_parent, &c->parent); + rimeaddr_copy(&c->parent, &n->addr); + if(enqueue_dummy_packet(c, PROACTIVE_MAINTENANCE_REXMITS)) { + send_queued_packet(c); + } + rimeaddr_copy(&c->parent, ¤t_parent); + break; + } + } + } return; } @@ -543,11 +614,32 @@ retransmit_current_packet(struct collect_conn *c) /* Get hold of the queuebuf. */ q = packetqueue_queuebuf(i); if(q != NULL) { + + update_rtmetric(c); + /* Place the queued packet into the packetbuf. */ queuebuf_to_packetbuf(q); - /* Pick the neighbor to which to send the packet. We use the - parent in the n->parent. */ + /* Pick the neighbor to which to send the packet. If we have found + a better parent while we were transmitting this packet, we + chose that neighbor instead. If so, we need to attribute the + transmissions we made for the parent to that neighbor. */ + if(!rimeaddr_cmp(&c->current_parent, &c->parent)) { + /* struct collect_neighbor *current_neighbor; + current_neighbor = collect_neighbor_list_find(&c->neighbor_list, + &c->current_parent); + if(current_neighbor != NULL) { + collect_neighbor_tx(current_neighbor, c->max_rexmits); + }*/ + + printf("parent change from %d.%d to %d.%d after %d tx\n", + c->current_parent.u8[0], c->current_parent.u8[1], + c->parent.u8[0], c->parent.u8[1], + c->transmissions); + + rimeaddr_copy(&c->current_parent, &c->parent); + c->transmissions = 0; + } n = collect_neighbor_list_find(&c->neighbor_list, &c->current_parent); if(n != NULL) { @@ -651,6 +743,8 @@ handle_ack(struct collect_conn *tc) if(!(msg->flags & ACK_FLAGS_DROPPED)) { send_next_packet(tc); + } else { + PRINTF("ack drop flag\n"); } if(msg->flags & ACK_FLAGS_RTMETRIC_NEEDS_UPDATE) { bump_advertisement(tc); @@ -666,8 +760,7 @@ send_ack(struct collect_conn *tc, const rimeaddr_t *to, int flags) { struct ack_msg *ack; uint16_t packet_seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID); - uint16_t packet_eseqno = packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID); - + packetbuf_clear(); packetbuf_set_datalen(sizeof(struct ack_msg)); ack = packetbuf_dataptr(); @@ -685,9 +778,8 @@ send_ack(struct collect_conn *tc, const rimeaddr_t *to, int flags) PRINTF("%d.%d: collect: Sending ACK to %d.%d for %d (epacket_id %d)\n", rimeaddr_node_addr.u8[0],rimeaddr_node_addr.u8[1], - to->u8[0], - to->u8[1], - packet_seqno, packet_eseqno); + to->u8[0], to->u8[1], packet_seqno, + packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID)); RIMESTATS_ADD(acktx); stats.acksent++; @@ -836,7 +928,7 @@ node_packet_received(struct unicast_conn *c, const rimeaddr_t *from) } else { send_ack(tc, &ack_to, ackflags | ACK_FLAGS_DROPPED | ACK_FLAGS_CONGESTED); - PRINTF("%d.%d: packet dropped: no queue buffer available\n", + printf("%d.%d: packet dropped: no queue buffer available\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); stats.qdrop++; } @@ -874,7 +966,7 @@ node_packet_sent(struct unicast_conn *c, int status, int transmissions) /* For data packets, we record the number of transmissions */ if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == - PACKETBUF_ATTR_PACKET_TYPE_DATA && transmissions > 0) { + PACKETBUF_ATTR_PACKET_TYPE_DATA) { tc->transmissions += transmissions; @@ -891,7 +983,7 @@ node_packet_sent(struct unicast_conn *c, int status, int transmissions) rexmit_time_scaling = 3; } time = REXMIT_TIME << rexmit_time_scaling; - time = time / 2 + random_rand() % (time / 2); + 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); @@ -902,8 +994,9 @@ static void timedout(struct collect_conn *tc) { struct collect_neighbor *n; - PRINTF("%d.%d: timedout after %d retransmissions (max retransmissions %d): packet dropped\n", + printf("%d.%d: timedout after %d retransmissions to %d.%d (max retransmissions %d): packet dropped\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], tc->transmissions, + tc->current_parent.u8[0], tc->current_parent.u8[1], tc->max_rexmits); tc->sending = 0; @@ -917,6 +1010,13 @@ timedout(struct collect_conn *tc) set_keepalive_timer(tc); } /*---------------------------------------------------------------------------*/ +/** + * 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 + * current packet, or timeout the packet. The descision is made + * depending on how many times the packet has been transmitted. The + * ctimer is set up in the function node_packet_sent(). + */ static void retransmit_callback(void *ptr) { @@ -981,10 +1081,14 @@ received_announcement(struct announcement *a, const rimeaddr_t *from, n = collect_neighbor_list_find(&tc->neighbor_list, from); if(n == NULL) { - collect_neighbor_list_add(&tc->neighbor_list, from, value); - PRINTF("%d.%d: new neighbor %d.%d, etx %d\n", - rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], - from->u8[0], from->u8[1], value); + /* Only add neighbors that have an rtmetric that is lower than + ours. */ + if(value < tc->rtmetric) { + collect_neighbor_list_add(&tc->neighbor_list, from, value); + PRINTF("%d.%d: new neighbor %d.%d, rtmetric %d\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], + from->u8[0], from->u8[1], value); + } if(value == RTMETRIC_MAX) { bump_advertisement(tc); } @@ -1062,37 +1166,15 @@ static void send_keepalive(void *ptr) { struct collect_conn *c = ptr; - struct collect_neighbor *n; set_keepalive_timer(c); /* Send keepalive message only if there are no pending transmissions. */ - if(packetqueue_len(&c->send_queue) == 0) { - packetbuf_clear(); - packetbuf_set_addr(PACKETBUF_ADDR_ESENDER, &rimeaddr_node_addr); - packetbuf_set_attr(PACKETBUF_ATTR_HOPS, 1); - packetbuf_set_attr(PACKETBUF_ATTR_TTL, 1); - packetbuf_set_attr(PACKETBUF_ATTR_MAX_REXMIT, KEEPALIVE_REXMITS); - - PRINTF("%d.%d: saending keepalive packet %d, max_rexmits %d\n", - rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], - packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID), - packetbuf_attr(PACKETBUF_ATTR_MAX_REXMIT)); - - /* Allocate space for the header. */ - packetbuf_hdralloc(sizeof(struct data_msg_hdr)); - - n = collect_neighbor_list_find(&c->neighbor_list, &c->parent); - if(n != NULL) { - PRINTF("%d.%d: sending keepalive to %d.%d\n", - rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1], - n->addr.u8[0], n->addr.u8[1]); - - if(packetqueue_enqueue_packetbuf(&c->send_queue, - FORWARD_PACKET_LIFETIME, - c)) { - send_queued_packet(c); - } + if(c->sending == 0 && packetqueue_len(&c->send_queue) == 0) { + if(enqueue_dummy_packet(c, KEEPALIVE_REXMITS)) { + PRINTF("%d.%d: sending keepalive\n", + rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); + send_queued_packet(c); } } } @@ -1204,7 +1286,7 @@ collect_send(struct collect_conn *tc, int rexmits) send_queued_packet(tc); return 1; } else { - PRINTF("%d.%d: drop originated packet: no queuebuf\n", + printf("%d.%d: drop originated packet: no queuebuf\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); } @@ -1228,7 +1310,7 @@ collect_send(struct collect_conn *tc, int rexmits) tc)) { return 1; } else { - PRINTF("%d.%d: drop originated packet: no queuebuf\n", + printf("%d.%d: drop originated packet: no queuebuf\n", rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]); } } diff --git a/core/net/rime/collect.h b/core/net/rime/collect.h index 5008357ac..2284659de 100644 --- a/core/net/rime/collect.h +++ b/core/net/rime/collect.h @@ -47,7 +47,7 @@ * * This file is part of the Contiki operating system. * - * $Id: collect.h,v 1.21 2010/09/22 22:08:08 adamdunkels Exp $ + * $Id: collect.h,v 1.22 2010/10/03 20:08:44 adamdunkels Exp $ */ /** @@ -75,7 +75,7 @@ { PACKETBUF_ATTR_PACKET_ID, PACKETBUF_ATTR_BIT * COLLECT_PACKET_ID_BITS }, \ { PACKETBUF_ATTR_TTL, PACKETBUF_ATTR_BIT * 4 }, \ { PACKETBUF_ATTR_HOPS, PACKETBUF_ATTR_BIT * 4 }, \ - { PACKETBUF_ATTR_MAX_REXMIT, PACKETBUF_ATTR_BIT * 4 }, \ + { PACKETBUF_ATTR_MAX_REXMIT, PACKETBUF_ATTR_BIT * 5 }, \ { PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_BIT }, \ UNICAST_ATTRIBUTES @@ -101,6 +101,8 @@ struct collect_conn { struct ctimer keepalive_timer; clock_time_t keepalive_period; + struct timer proactive_maintenence_timer; + rimeaddr_t parent, current_parent; uint16_t rtmetric; uint8_t seqno; @@ -129,7 +131,7 @@ void collect_set_keepalive(struct collect_conn *c, clock_time_t period); void collect_print_stats(void); -#define COLLECT_MAX_DEPTH 255 +#define COLLECT_MAX_DEPTH ((1 << 12) - 1) #endif /* __COLLECT_H__ */ /** @} */