From f5031861acdcd4045c06833052ec547a7d778162 Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Thu, 28 Oct 2010 15:42:56 +0000 Subject: [PATCH] When IPv6 ND kicks in, the packet that caused the ND can either be dropped or saved in a buffer to be send when the NS reply returns. This commit reimplements the buffer management to avoid having one buffer per neighbor, but instead use a buffer pool from which buffers can be allocated for different neighbors. --- core/net/uip-ds6.c | 58 +++++++++++++++---------- core/net/uip-ds6.h | 13 +++--- core/net/uip-nd6.c | 19 ++++++++- core/net/uip-packetqueue.c | 86 ++++++++++++++++++++++++++++++++++++++ core/net/uip-packetqueue.h | 35 ++++++++++++++++ 5 files changed, 182 insertions(+), 29 deletions(-) create mode 100644 core/net/uip-packetqueue.c create mode 100644 core/net/uip-packetqueue.h diff --git a/core/net/uip-ds6.c b/core/net/uip-ds6.c index a5e680e5e..f6eaaaeea 100755 --- a/core/net/uip-ds6.c +++ b/core/net/uip-ds6.c @@ -45,6 +45,7 @@ #include "lib/random.h" #include "net/uip-nd6.h" #include "net/uip-ds6.h" +#include "net/uip-packetqueue.h" #define DEBUG 0 #if DEBUG @@ -268,6 +269,7 @@ uip_ds6_list_loop(uip_ds6_element_t * list, uint8_t size, element < (uip_ds6_element_t *) ((uint8_t *) list + (size * elementsize)); element = (uip_ds6_element_t *) ((uint8_t *) element + elementsize)) { + // printf("+ %p %d\n", &element->isused, element->isused); if(element->isused) { if(uip_ipaddr_prefixcmp(&(element->ipaddr), ipaddr, ipaddrlen)) { *out_element = element; @@ -278,7 +280,7 @@ uip_ds6_list_loop(uip_ds6_element_t * list, uint8_t size, } } - if(*out_element) { + if(*out_element != NULL) { return FREESPACE; } else { return NOSPACE; @@ -290,10 +292,15 @@ uip_ds6_nbr_t * uip_ds6_nbr_add(uip_ipaddr_t * ipaddr, uip_lladdr_t * lladdr, uint8_t isrouter, uint8_t state) { - if(uip_ds6_list_loop + int r; + + r = uip_ds6_list_loop ((uip_ds6_element_t *) uip_ds6_nbr_cache, UIP_DS6_NBR_NB, sizeof(uip_ds6_nbr_t), ipaddr, 128, - (uip_ds6_element_t **) & locnbr) == FREESPACE) { + (uip_ds6_element_t **) &locnbr); + // printf("r %d\n", r); + + if(r == FREESPACE) { locnbr->isused = 1; uip_ipaddr_copy(&(locnbr->ipaddr), ipaddr); if(lladdr != NULL) { @@ -303,6 +310,9 @@ uip_ds6_nbr_add(uip_ipaddr_t * ipaddr, uip_lladdr_t * lladdr, } locnbr->isrouter = isrouter; locnbr->state = state; +#if UIP_CONF_IPV6_QUEUE_PKT + uip_packetqueue_new(&locnbr->packethandle); +#endif /* UIP_CONF_IPV6_QUEUE_PKT */ /* timers are set separately, for now we put them in expired state */ stimer_set(&(locnbr->reachable), 0); stimer_set(&(locnbr->sendns), 0); @@ -315,31 +325,31 @@ uip_ds6_nbr_add(uip_ipaddr_t * ipaddr, uip_lladdr_t * lladdr, NEIGHBOR_STATE_CHANGED(locnbr); locnbr->last_lookup = clock_time(); + // printf("add %p\n", locnbr); return locnbr; - } else { + } else if(r == NOSPACE) { /* We did not find any empty slot on the neighbor list, so we need to remove one old entry to make room. */ - { - uip_ds6_nbr_t *n, *oldest; - clock_time_t oldest_time; + uip_ds6_nbr_t *n, *oldest; + clock_time_t oldest_time; - oldest = NULL; - oldest_time = 0 - 1UL; + oldest = NULL; + oldest_time = clock_time(); - for(n = uip_ds6_nbr_cache; - n < &uip_ds6_nbr_cache[UIP_DS6_NBR_NB]; - n++) { - if(n->isused) { - if(n->last_lookup < oldest_time) { - oldest = n; - oldest_time = n->last_lookup; - } + for(n = uip_ds6_nbr_cache; + n < &uip_ds6_nbr_cache[UIP_DS6_NBR_NB]; + n++) { + if(n->isused) { + if(n->last_lookup < oldest_time) { + oldest = n; + oldest_time = n->last_lookup; } } - if(oldest != NULL) { - uip_ds6_nbr_rm(oldest); - return uip_ds6_nbr_add(ipaddr, lladdr, isrouter, state); - } + } + if(oldest != NULL) { + // printf("rm3\n"); + uip_ds6_nbr_rm(oldest); + return uip_ds6_nbr_add(ipaddr, lladdr, isrouter, state); } } PRINTF("uip_ds6_nbr_add drop\n"); @@ -352,7 +362,11 @@ uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr) { if(nbr != NULL) { nbr->isused = 0; - NEIGHBOR_STATE_CHANGED(nbr); +#if UIP_CONF_IPV6_QUEUE_PKT + // printf("rm %p\n", &nbr->isused); + uip_packetqueue_free(&nbr->packethandle); +#endif /* UIP_CONF_IPV6_QUEUE_PKT */ + // NEIGHBOR_STATE_CHANGED(nbr); } return; } diff --git a/core/net/uip-ds6.h b/core/net/uip-ds6.h index 7bfff119e..7b9f4cf71 100755 --- a/core/net/uip-ds6.h +++ b/core/net/uip-ds6.h @@ -152,20 +152,23 @@ /*--------------------------------------------------*/ +#if UIP_CONF_IPV6_QUEUE_PKT +#include "net/uip-packetqueue.h" +#endif /*UIP_CONF_QUEUE_PKT */ /** \brief An entry in the nbr cache */ typedef struct uip_ds6_nbr { uint8_t isused; uip_ipaddr_t ipaddr; uip_lladdr_t lladdr; - uint8_t isrouter; - uint8_t state; struct stimer reachable; struct stimer sendns; - uint8_t nscount; clock_time_t last_lookup; + uint8_t nscount; + uint8_t isrouter; + uint8_t state; #if UIP_CONF_IPV6_QUEUE_PKT - uint8_t queue_buf[UIP_BUFSIZE - UIP_LLH_LEN]; - uint8_t queue_buf_len; + struct uip_packetqueue_handle packethandle; +#define UIP_DS6_NBR_PACKET_LIFETIME CLOCK_SECOND * 4 #endif /*UIP_CONF_QUEUE_PKT */ } uip_ds6_nbr_t; diff --git a/core/net/uip-nd6.c b/core/net/uip-nd6.c index 8bd60fe5d..1874cec51 100644 --- a/core/net/uip-nd6.c +++ b/core/net/uip-nd6.c @@ -135,6 +135,7 @@ static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/ static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */ static uip_ds6_addr_t *addr; /** Pointer to an interface address */ + /*------------------------------------------------------------------*/ /* create a llao */ static void @@ -507,12 +508,19 @@ uip_nd6_na_input(void) } #if UIP_CONF_IPV6_QUEUE_PKT /* The nbr is now reachable, check if we had buffered a pkt for it */ - if(nbr->queue_buf_len != 0) { + /*if(nbr->queue_buf_len != 0) { uip_len = nbr->queue_buf_len; memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len); nbr->queue_buf_len = 0; return; + }*/ + if(uip_packetqueue_buflen(&nbr->packethandle) != 0) { + uip_len = uip_packetqueue_buflen(&nbr->packethandle); + memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); + uip_packetqueue_free(&nbr->packethandle); + return; } + #endif /*UIP_CONF_IPV6_QUEUE_PKT */ discard: @@ -918,12 +926,19 @@ uip_nd6_ra_input(void) #if UIP_CONF_IPV6_QUEUE_PKT /* If the nbr just became reachable (e.g. it was in NBR_INCOMPLETE state * and we got a SLLAO), check if we had buffered a pkt for it */ - if((nbr != NULL) && (nbr->queue_buf_len != 0)) { + /* if((nbr != NULL) && (nbr->queue_buf_len != 0)) { uip_len = nbr->queue_buf_len; memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len); nbr->queue_buf_len = 0; return; + }*/ + if(nbr != NULL && uip_packetqueue_buflen(&nbr->packethandle) != 0) { + uip_len = uip_packetqueue_buflen(&nbr->packethandle); + memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); + uip_packetqueue_free(&nbr->packethandle); + return; } + #endif /*UIP_CONF_IPV6_QUEUE_PKT */ discard: diff --git a/core/net/uip-packetqueue.c b/core/net/uip-packetqueue.c new file mode 100644 index 000000000..f9b9c2d80 --- /dev/null +++ b/core/net/uip-packetqueue.c @@ -0,0 +1,86 @@ +#include + +#include "net/uip.h" + +#include "lib/memb.h" + +#include "net/uip-packetqueue.h" + +#define MAX_NUM_QUEUED_PACKETS 2 +MEMB(packets_memb, struct uip_packetqueue_packet, MAX_NUM_QUEUED_PACKETS); + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +/*---------------------------------------------------------------------------*/ +static void +packet_timedout(void *ptr) +{ + struct uip_packetqueue_handle *h = ptr; + + PRINTF("uip_packetqueue_free timed out %p\n", h); + memb_free(&packets_memb, h->packet); + h->packet = NULL; +} +/*---------------------------------------------------------------------------*/ +void +uip_packetqueue_new(struct uip_packetqueue_handle *handle) +{ + PRINTF("uip_packetqueue_new %p\n", handle); + handle->packet = NULL; +} +/*---------------------------------------------------------------------------*/ +struct uip_packetqueue_packet * +uip_packetqueue_alloc(struct uip_packetqueue_handle *handle, clock_time_t lifetime) +{ + PRINTF("uip_packetqueue_alloc %p\n", handle); + if(handle->packet != NULL) { + PRINTF("alloced\n"); + return NULL; + } + handle->packet = memb_alloc(&packets_memb); + if(handle->packet != NULL) { + ctimer_set(&handle->packet->lifetimer, lifetime, + packet_timedout, handle); + } else { + PRINTF("uip_packetqueue_alloc failed\n"); + } + return handle->packet; +} +/*---------------------------------------------------------------------------*/ +void +uip_packetqueue_free(struct uip_packetqueue_handle *handle) +{ + PRINTF("uip_packetqueue_free %p\n", handle); + if(handle->packet != NULL) { + ctimer_stop(&handle->packet->lifetimer); + memb_free(&packets_memb, handle->packet); + handle->packet = NULL; + } +} +/*---------------------------------------------------------------------------*/ +uint8_t * +uip_packetqueue_buf(struct uip_packetqueue_handle *h) +{ + return h->packet != NULL? h->packet->queue_buf: NULL; +} +/*---------------------------------------------------------------------------*/ +uint16_t +uip_packetqueue_buflen(struct uip_packetqueue_handle *h) +{ + return h->packet != NULL? h->packet->queue_buf_len: 0; +} +/*---------------------------------------------------------------------------*/ +void +uip_packetqueue_set_buflen(struct uip_packetqueue_handle *h, uint16_t len) +{ + if(h->packet != NULL) { + h->packet->queue_buf_len = len; + } +} +/*---------------------------------------------------------------------------*/ diff --git a/core/net/uip-packetqueue.h b/core/net/uip-packetqueue.h new file mode 100644 index 000000000..b265b1ecf --- /dev/null +++ b/core/net/uip-packetqueue.h @@ -0,0 +1,35 @@ +#ifndef UIP_PACKETQUEUE_H +#define UIP_PACKETQUEUE_H + +#include "sys/ctimer.h" + +struct uip_packetqueue_handle; + +struct uip_packetqueue_packet { + struct uip_ds6_queued_packet *next; + uint8_t queue_buf[UIP_BUFSIZE - UIP_LLH_LEN]; + uint16_t queue_buf_len; + struct ctimer lifetimer; + struct uip_packetqueue_handle *handle; +}; + +struct uip_packetqueue_handle { + struct uip_packetqueue_packet *packet; +}; + +void uip_packetqueue_new(struct uip_packetqueue_handle *handle); + + +struct uip_packetqueue_packet * +uip_packetqueue_alloc(struct uip_packetqueue_handle *handle, clock_time_t lifetime); + + +void +uip_packetqueue_free(struct uip_packetqueue_handle *handle); + +uint8_t *uip_packetqueue_buf(struct uip_packetqueue_handle *h); +uint16_t uip_packetqueue_buflen(struct uip_packetqueue_handle *h); +void uip_packetqueue_set_buflen(struct uip_packetqueue_handle *h, uint16_t len); + + +#endif /* UIP_PACKETQUEUE_H */