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.

This commit is contained in:
adamdunkels 2010-10-28 15:42:56 +00:00
parent 677575fc8c
commit f5031861ac
5 changed files with 182 additions and 29 deletions

View file

@ -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,16 +325,16 @@ 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;
oldest = NULL;
oldest_time = 0 - 1UL;
oldest_time = clock_time();
for(n = uip_ds6_nbr_cache;
n < &uip_ds6_nbr_cache[UIP_DS6_NBR_NB];
@ -337,11 +347,11 @@ uip_ds6_nbr_add(uip_ipaddr_t * ipaddr, uip_lladdr_t * lladdr,
}
}
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");
return NULL;
}
@ -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;
}

View file

@ -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;

View file

@ -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:

View file

@ -0,0 +1,86 @@
#include <stdio.h>
#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 <stdio.h>
#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;
}
}
/*---------------------------------------------------------------------------*/

View file

@ -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 */