Rework of the CSMA layer: instead of using one timer per packet, the module now uses one central timer and a queue of outgoing packets. This helps to keep packets in order, which is extremely useful for TCP transfers, and reduces the amount of congestion since consecutive packets now are spaced in time if there is a collision. Based on the observations and ideas of Simon Duquennoy.
This commit is contained in:
parent
a9dedfee4f
commit
952dfc9384
|
@ -28,7 +28,7 @@
|
||||||
*
|
*
|
||||||
* This file is part of the Contiki operating system.
|
* This file is part of the Contiki operating system.
|
||||||
*
|
*
|
||||||
* $Id: csma.c,v 1.22 2010/10/24 21:07:00 adamdunkels Exp $
|
* $Id: csma.c,v 1.23 2010/12/14 07:57:14 adamdunkels Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,6 +53,8 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -77,36 +79,62 @@
|
||||||
struct queued_packet {
|
struct queued_packet {
|
||||||
struct queued_packet *next;
|
struct queued_packet *next;
|
||||||
struct queuebuf *buf;
|
struct queuebuf *buf;
|
||||||
struct ctimer retransmit_timer;
|
/* struct ctimer retransmit_timer;*/
|
||||||
mac_callback_t sent;
|
mac_callback_t sent;
|
||||||
void *cptr;
|
void *cptr;
|
||||||
uint8_t transmissions, max_transmissions;
|
uint8_t transmissions, max_transmissions;
|
||||||
uint8_t collisions, deferrals;
|
uint8_t collisions, deferrals;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_QUEUED_PACKETS 8
|
#define MAX_QUEUED_PACKETS 4
|
||||||
MEMB(packet_memb, struct queued_packet, MAX_QUEUED_PACKETS);
|
MEMB(packet_memb, struct queued_packet, MAX_QUEUED_PACKETS);
|
||||||
|
LIST(queued_packet_list);
|
||||||
|
|
||||||
|
static struct ctimer transmit_timer;
|
||||||
|
|
||||||
static void packet_sent(void *ptr, int status, int num_transmissions);
|
static void packet_sent(void *ptr, int status, int num_transmissions);
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
retransmit_packet(void *ptr)
|
transmit_queued_packet(void *ptr)
|
||||||
{
|
{
|
||||||
struct queued_packet *q = ptr;
|
/* struct queued_packet *q = ptr;*/
|
||||||
|
struct queued_packet *q;
|
||||||
|
|
||||||
|
q = list_head(queued_packet_list);
|
||||||
|
|
||||||
|
if(q != NULL) {
|
||||||
queuebuf_to_packetbuf(q->buf);
|
queuebuf_to_packetbuf(q->buf);
|
||||||
PRINTF("csma: resending number %d %p\n", q->transmissions, q);
|
PRINTF("csma: resending number %d %p\n", q->transmissions, q);
|
||||||
NETSTACK_RDC.send(packet_sent, q);
|
NETSTACK_RDC.send(packet_sent, q);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
free_packet(struct queued_packet *q)
|
start_transmission_timer(void)
|
||||||
{
|
{
|
||||||
// printf("free_packet %p\n", q);
|
if(list_length(queued_packet_list) > 0) {
|
||||||
ctimer_stop(&q->retransmit_timer);
|
if(ctimer_expired(&transmit_timer)) {
|
||||||
|
ctimer_set(&transmit_timer, 0, transmit_queued_packet, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
free_queued_packet(void)
|
||||||
|
{
|
||||||
|
struct queued_packet *q;
|
||||||
|
|
||||||
|
q = list_head(queued_packet_list);
|
||||||
|
|
||||||
|
if(q != NULL) {
|
||||||
queuebuf_free(q->buf);
|
queuebuf_free(q->buf);
|
||||||
|
list_remove(queued_packet_list, q);
|
||||||
memb_free(&packet_memb, q);
|
memb_free(&packet_memb, q);
|
||||||
|
if(list_length(queued_packet_list) > 0) {
|
||||||
|
ctimer_set(&transmit_timer, 0, transmit_queued_packet, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
|
@ -117,8 +145,7 @@ packet_sent(void *ptr, int status, int num_transmissions)
|
||||||
mac_callback_t sent;
|
mac_callback_t sent;
|
||||||
void *cptr;
|
void *cptr;
|
||||||
int num_tx;
|
int num_tx;
|
||||||
|
int backoff_transmissions;
|
||||||
// printf("packet_sent %p\n", q);
|
|
||||||
|
|
||||||
switch(status) {
|
switch(status) {
|
||||||
case MAC_TX_OK:
|
case MAC_TX_OK:
|
||||||
|
@ -168,17 +195,25 @@ packet_sent(void *ptr, int status, int num_transmissions)
|
||||||
/* The retransmission time uses a linear backoff so that the
|
/* The retransmission time uses a linear backoff so that the
|
||||||
interval between the transmissions increase with each
|
interval between the transmissions increase with each
|
||||||
retransmit. */
|
retransmit. */
|
||||||
time = time + (random_rand() % ((q->transmissions + 1) * 2 * time));
|
backoff_transmissions = q->transmissions + 1;
|
||||||
|
|
||||||
if(q->transmissions + q->collisions < q->max_transmissions) {
|
/* Clamp the number of backoffs so that we don't get a too long
|
||||||
|
timeout here, since that will delay all packets in the
|
||||||
|
queue. */
|
||||||
|
if(backoff_transmissions > 3) {
|
||||||
|
backoff_transmissions = 3;
|
||||||
|
}
|
||||||
|
time = time + (random_rand() % ((backoff_transmissions) * time));
|
||||||
|
|
||||||
|
if(q->transmissions < q->max_transmissions) {
|
||||||
PRINTF("csma: retransmitting with time %lu %p\n", time, q);
|
PRINTF("csma: retransmitting with time %lu %p\n", time, q);
|
||||||
ctimer_set(&q->retransmit_timer, time,
|
ctimer_set(&transmit_timer, time,
|
||||||
retransmit_packet, q);
|
transmit_queued_packet, NULL);
|
||||||
} else {
|
} else {
|
||||||
PRINTF("csma: drop after %d\n", q->transmissions);
|
PRINTF("csma: drop with status %d after %d transmissions, %d collisions\n",
|
||||||
queuebuf_to_packetbuf(q->buf);
|
status, q->transmissions, q->collisions);
|
||||||
free_packet(q);
|
/* queuebuf_to_packetbuf(q->buf);*/
|
||||||
// printf("call 1 %p\n", cptr);
|
free_queued_packet();
|
||||||
mac_call_sent_callback(sent, cptr, status, num_tx);
|
mac_call_sent_callback(sent, cptr, status, num_tx);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -187,9 +222,8 @@ packet_sent(void *ptr, int status, int num_transmissions)
|
||||||
} else {
|
} else {
|
||||||
PRINTF("csma: rexmit failed %d: %d\n", q->transmissions, status);
|
PRINTF("csma: rexmit failed %d: %d\n", q->transmissions, status);
|
||||||
}
|
}
|
||||||
queuebuf_to_packetbuf(q->buf);
|
/* queuebuf_to_packetbuf(q->buf);*/
|
||||||
free_packet(q);
|
free_queued_packet();
|
||||||
// printf("call 2 %p\n", cptr);
|
|
||||||
mac_call_sent_callback(sent, cptr, status, num_tx);
|
mac_call_sent_callback(sent, cptr, status, num_tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,10 +236,15 @@ send_packet(mac_callback_t sent, void *ptr)
|
||||||
|
|
||||||
packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
|
packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, seqno++);
|
||||||
|
|
||||||
|
/* If the packet is a broadcast, do not allocate a queue
|
||||||
|
entry. Instead, just send it out. */
|
||||||
|
if(!rimeaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
|
||||||
|
&rimeaddr_null) &&
|
||||||
|
packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS > 0)) {
|
||||||
|
|
||||||
/* Remember packet for later. */
|
/* Remember packet for later. */
|
||||||
q = memb_alloc(&packet_memb);
|
q = memb_alloc(&packet_memb);
|
||||||
if(q != NULL) {
|
if(q != NULL) {
|
||||||
// printf("send_packet %p\n", q);
|
|
||||||
q->buf = queuebuf_new_from_packetbuf();
|
q->buf = queuebuf_new_from_packetbuf();
|
||||||
if(q != NULL) {
|
if(q != NULL) {
|
||||||
if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) {
|
if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) {
|
||||||
|
@ -220,12 +259,15 @@ send_packet(mac_callback_t sent, void *ptr)
|
||||||
q->deferrals = 0;
|
q->deferrals = 0;
|
||||||
q->sent = sent;
|
q->sent = sent;
|
||||||
q->cptr = ptr;
|
q->cptr = ptr;
|
||||||
NETSTACK_RDC.send(packet_sent, q);
|
list_add(queued_packet_list, q);
|
||||||
|
start_transmission_timer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memb_free(&packet_memb, q);
|
memb_free(&packet_memb, q);
|
||||||
}
|
|
||||||
PRINTF("csma: could not allocate queuebuf, will drop if collision or noack\n");
|
PRINTF("csma: could not allocate queuebuf, will drop if collision or noack\n");
|
||||||
|
}
|
||||||
|
PRINTF("csma: could not allocate memb, will drop if collision or noack\n");
|
||||||
|
}
|
||||||
NETSTACK_RDC.send(sent, ptr);
|
NETSTACK_RDC.send(sent, ptr);
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
Loading…
Reference in a new issue