uip-ds6-nbr: introduce UIP_DS6_NBR_MULTI_IPV6_ADDRS

This feature, which is disabled by default, extends the neighbor cache
management in order to have multiple IPv6 address associated with a
single link-layer address as neighbor caches.

To use this feature, set 1 to UIP_DS6_NBR_CONF_MAX_NEIGHBOR_CACHES.
This commit is contained in:
Yasuyuki Tanaka 2018-04-01 12:50:31 +02:00 committed by Yasuyuki Tanaka
parent 8ef5c8b8c6
commit ee452b5287
2 changed files with 303 additions and 23 deletions

View File

@ -55,19 +55,40 @@
#include "net/ipv6/uip-nd6.h"
#include "net/routing/routing.h"
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
#include "lib/memb.h"
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
/* Log configuration */
#include "sys/log.h"
#define LOG_MODULE "IPv6 Nbr"
#define LOG_LEVEL LOG_LEVEL_IPV6
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
static void add_uip_ds6_nbr_to_nbr_entry(uip_ds6_nbr_t *nbr,
uip_ds6_nbr_entry_t *nbr_entry);
static void remove_uip_ds6_nbr_from_nbr_entry(uip_ds6_nbr_t *nbr);
static void remove_nbr_entry(uip_ds6_nbr_entry_t *nbr_entry);
static void free_uip_ds6_nbr(uip_ds6_nbr_t *nbr);
static void callback_nbr_entry_removal(uip_ds6_nbr_entry_t *nbr_entry);
NBR_TABLE(uip_ds6_nbr_entry_t, uip_ds6_nbr_entries);
MEMB(uip_ds6_nbr_memb, uip_ds6_nbr_t, UIP_DS6_NBR_MAX_NEIGHBOR_CACHES);
#else
NBR_TABLE(uip_ds6_nbr_t, ds6_neighbors);
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
/*---------------------------------------------------------------------------*/
void
uip_ds6_neighbors_init(void)
{
link_stats_init();
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
memb_init(&uip_ds6_nbr_memb);
nbr_table_register(uip_ds6_nbr_entries,
(nbr_table_callback *)callback_nbr_entry_removal);
#else
nbr_table_register(ds6_neighbors, (nbr_table_callback *)uip_ds6_nbr_rm);
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
}
/*---------------------------------------------------------------------------*/
uip_ds6_nbr_t *
@ -75,8 +96,44 @@ uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr,
uint8_t isrouter, uint8_t state, nbr_table_reason_t reason,
void *data)
{
uip_ds6_nbr_t *nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr
, reason, data);
uip_ds6_nbr_t *nbr;
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
uip_ds6_nbr_entry_t *nbr_entry;
assert(uip_ds6_nbr_lookup(ipaddr) == NULL);
if(uip_ds6_nbr_lookup(ipaddr)) {
LOG_ERR("%s: uip_ds6_nbr for ", __func__);
LOG_ERR_6ADDR(ipaddr);
LOG_ERR_("has already existed\n");
return NULL;
}
nbr_entry = nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
(const linkaddr_t *)lladdr);
if(nbr_entry == NULL) {
if((nbr_entry =
nbr_table_add_lladdr(uip_ds6_nbr_entries,
(linkaddr_t*)lladdr, reason, data)) == NULL) {
LOG_ERR("%s: cannot allocate a new uip_ds6_nbr_entry\n", __func__);
return NULL;
} else {
LIST_STRUCT_INIT(nbr_entry, uip_ds6_nbrs);
}
}
if((nbr = (uip_ds6_nbr_t *)memb_alloc(&uip_ds6_nbr_memb)) == NULL) {
LOG_ERR("%s: cannot allocate a new uip_ds6_nbr\n", __func__);
if(list_length(nbr_entry->uip_ds6_nbrs) == 0) {
nbr_table_remove(uip_ds6_nbr_entries, nbr_entry);
}
} else {
add_uip_ds6_nbr_to_nbr_entry(nbr, nbr_entry);
}
#else
nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr, reason, data);
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
if(nbr) {
uip_ipaddr_copy(&nbr->ipaddr, ipaddr);
#if UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
@ -113,10 +170,91 @@ uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr,
}
}
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
/*---------------------------------------------------------------------------*/
static void
add_uip_ds6_nbr_to_nbr_entry(uip_ds6_nbr_t *nbr,
uip_ds6_nbr_entry_t *nbr_entry)
{
LOG_DBG("%s: add nbr(%p) to nbr_entry (%p)\n",
__func__, nbr, nbr_entry);
nbr->nbr_entry = nbr_entry;
list_add(nbr_entry->uip_ds6_nbrs, nbr);
}
/*---------------------------------------------------------------------------*/
static void
remove_uip_ds6_nbr_from_nbr_entry(uip_ds6_nbr_t *nbr)
{
if(nbr == NULL) {
return;
}
LOG_DBG("%s: remove nbr(%p) from nbr_entry (%p)\n",
__func__, nbr, nbr->nbr_entry);
list_remove(nbr->nbr_entry->uip_ds6_nbrs, nbr);
}
/*---------------------------------------------------------------------------*/
static void
remove_nbr_entry(uip_ds6_nbr_entry_t *nbr_entry)
{
if(nbr_entry == NULL) {
return;
}
LOG_DBG("%s: remove nbr_entry (%p) from nbr_table\n",
__func__, nbr_entry);
(void)nbr_table_remove(uip_ds6_nbr_entries, nbr_entry);
}
/*---------------------------------------------------------------------------*/
static void
free_uip_ds6_nbr(uip_ds6_nbr_t *nbr)
{
if(nbr == NULL) {
return;
}
#if UIP_CONF_IPV6_QUEUE_PKT
uip_packetqueue_free(&nbr->packethandle);
#endif /* UIP_CONF_IPV6_QUEUE_PKT */
NETSTACK_ROUTING.neighbor_state_changed(nbr);
assert(nbr->nbr_entry != NULL);
if(nbr->nbr_entry == NULL) {
LOG_ERR("%s: unexpected error nbr->nbr_entry is NULL\n", __func__);
} else {
remove_uip_ds6_nbr_from_nbr_entry(nbr);
if(list_length(nbr->nbr_entry->uip_ds6_nbrs) == 0) {
remove_nbr_entry(nbr->nbr_entry);
}
}
LOG_DBG("%s: free memory for nbr(%p)\n", __func__, nbr);
memb_free(&uip_ds6_nbr_memb, nbr);
}
/*---------------------------------------------------------------------------*/
static void
callback_nbr_entry_removal(uip_ds6_nbr_entry_t *nbr_entry)
{
uip_ds6_nbr_t *nbr;
uip_ds6_nbr_t *next_nbr;
if(nbr_entry == NULL) {
return;
}
for(nbr = (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
nbr != NULL;
nbr = next_nbr) {
next_nbr = (uip_ds6_nbr_t *)list_item_next(nbr);
free_uip_ds6_nbr(nbr);
}
}
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
/*---------------------------------------------------------------------------*/
int
uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr)
{
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
if(nbr == NULL) {
return 0;
} else {
free_uip_ds6_nbr(nbr);
return 1;
}
#else /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
if(nbr != NULL) {
#if UIP_CONF_IPV6_QUEUE_PKT
uip_packetqueue_free(&nbr->packethandle);
@ -125,19 +263,52 @@ uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr)
return nbr_table_remove(ds6_neighbors, nbr);
}
return 0;
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
}
/*---------------------------------------------------------------------------*/
int
uip_ds6_nbr_update_ll(uip_ds6_nbr_t **nbr_pp, const uip_lladdr_t *new_ll_addr)
{
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
uip_ds6_nbr_entry_t *nbr_entry;
uip_ds6_nbr_t *nbr;
#else
uip_ds6_nbr_t nbr_backup;
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
if(nbr_pp == NULL || new_ll_addr == NULL) {
LOG_ERR("%s: invalid argument\n", __func__);
return -1;
}
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
if((nbr_entry =
nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
(const linkaddr_t *)new_ll_addr)) == NULL) {
if((nbr_entry =
nbr_table_add_lladdr(uip_ds6_nbr_entries,
(const linkaddr_t*)new_ll_addr,
NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
LOG_ERR("%s: cannot allocate a nbr_entry for", __func__);
LOG_ERR_LLADDR((const linkaddr_t *)new_ll_addr);
return -1;
} else {
LIST_STRUCT_INIT(nbr_entry, uip_ds6_nbrs);
}
}
nbr = *nbr_pp;
remove_uip_ds6_nbr_from_nbr_entry(nbr);
if(list_length(nbr->nbr_entry->uip_ds6_nbrs) == 0) {
remove_nbr_entry(nbr->nbr_entry);
}
add_uip_ds6_nbr_to_nbr_entry(nbr, nbr_entry);
#else /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
/* make sure new_ll_addr is not used in some other nbr */
if(uip_ds6_nbr_ll_lookup(new_ll_addr) != NULL) {
LOG_ERR("%s: new_ll_addr, ", __func__);
@ -159,6 +330,7 @@ uip_ds6_nbr_update_ll(uip_ds6_nbr_t **nbr_pp, const uip_lladdr_t *new_ll_addr)
return -1;
}
memcpy(*nbr_pp, &nbr_backup, sizeof(uip_ds6_nbr_t));
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
return 0;
}
@ -173,47 +345,89 @@ uip_ds6_nbr_get_ipaddr(const uip_ds6_nbr_t *nbr)
const uip_lladdr_t *
uip_ds6_nbr_get_ll(const uip_ds6_nbr_t *nbr)
{
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
if(nbr == NULL) {
return NULL;
}
return (const uip_lladdr_t *)nbr_table_get_lladdr(uip_ds6_nbr_entries,
nbr->nbr_entry);
#else
return (const uip_lladdr_t *)nbr_table_get_lladdr(ds6_neighbors, nbr);
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
}
/*---------------------------------------------------------------------------*/
int
uip_ds6_nbr_num(void)
{
uip_ds6_nbr_t *nbr;
int num;
int num = 0;
num = 0;
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
uip_ds6_nbr_entry_t *nbr_entry;
for(nbr_entry = nbr_table_head(uip_ds6_nbr_entries);
nbr_entry != NULL;
nbr_entry = nbr_table_next(uip_ds6_nbr_entries, nbr_entry)) {
num += list_length(nbr_entry->uip_ds6_nbrs);
}
#else
uip_ds6_nbr_t *nbr;
for(nbr = nbr_table_head(ds6_neighbors);
nbr != NULL;
nbr = nbr_table_next(ds6_neighbors, nbr)) {
num++;
}
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
return num;
}
/*---------------------------------------------------------------------------*/
uip_ds6_nbr_t *
uip_ds6_nbr_head(void)
{
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
uip_ds6_nbr_entry_t *nbr_entry;
if((nbr_entry = nbr_table_head(uip_ds6_nbr_entries)) == NULL) {
return NULL;
}
assert(list_head(nbr_entry->uip_ds6_nbrs) != NULL);
return (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
#else
return nbr_table_head(ds6_neighbors);
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
}
/*---------------------------------------------------------------------------*/
uip_ds6_nbr_t *
uip_ds6_nbr_next(uip_ds6_nbr_t *nbr)
{
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
uip_ds6_nbr_entry_t *nbr_entry;
if(nbr == NULL) {
return NULL;
}
if(list_item_next(nbr) != NULL) {
return list_item_next(nbr);
}
nbr_entry = nbr_table_next(uip_ds6_nbr_entries, nbr->nbr_entry);
if(nbr_entry == NULL) {
return NULL;
} else {
assert(list_head(nbr_entry->uip_ds6_nbrs) != NULL);
return (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
}
#else
return nbr_table_next(ds6_neighbors, nbr);
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
}
/*---------------------------------------------------------------------------*/
uip_ds6_nbr_t *
uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
{
uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
if(ipaddr != NULL) {
while(nbr != NULL) {
uip_ds6_nbr_t *nbr;
if(ipaddr == NULL) {
return NULL;
}
for(nbr = uip_ds6_nbr_head(); nbr != NULL; nbr = uip_ds6_nbr_next(nbr)) {
if(uip_ipaddr_cmp(&nbr->ipaddr, ipaddr)) {
return nbr;
}
nbr = nbr_table_next(ds6_neighbors, nbr);
}
}
return NULL;
}
@ -221,7 +435,23 @@ uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
uip_ds6_nbr_t *
uip_ds6_nbr_ll_lookup(const uip_lladdr_t *lladdr)
{
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
uip_ds6_nbr_entry_t *nbr_entry;
/*
* we cannot determine which entry should return by lladdr alone;
* return the first entry associated with lladdr.
*/
nbr_entry =
(uip_ds6_nbr_entry_t *)nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
(linkaddr_t*)lladdr);
if(nbr_entry == NULL) {
return NULL;
}
assert(list_head(nbr_entry->uip_ds6_nbrs) != NULL);
return (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
#else
return nbr_table_get_from_lladdr(ds6_neighbors, (linkaddr_t*)lladdr);
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
}
/*---------------------------------------------------------------------------*/
@ -239,6 +469,20 @@ uip_ds6_nbr_lladdr_from_ipaddr(const uip_ipaddr_t *ipaddr)
uip_ds6_nbr_t *nbr = uip_ds6_nbr_lookup(ipaddr);
return nbr ? uip_ds6_nbr_get_ll(nbr) : NULL;
}
#if UIP_DS6_LL_NUD
/*---------------------------------------------------------------------------*/
static void
update_nbr_reachable_state_by_ack(uip_ds6_nbr_t *nbr, const linkaddr_t *lladdr)
{
if(nbr != NULL && nbr->state != NBR_INCOMPLETE) {
nbr->state = NBR_REACHABLE;
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
LOG_INFO("received a link layer ACK : ");
LOG_INFO_LLADDR(lladdr);
LOG_INFO_(" is reachable.\n");
}
}
#endif /* UIP_DS6_LL_NUD */
/*---------------------------------------------------------------------------*/
void
uip_ds6_link_callback(int status, int numtx)
@ -266,14 +510,22 @@ uip_ds6_link_callback(int status, int numtx)
* acknowledges link packets. */
if(status == MAC_TX_OK) {
uip_ds6_nbr_t *nbr;
nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest);
if(nbr != NULL && nbr->state != NBR_INCOMPLETE) {
nbr->state = NBR_REACHABLE;
stimer_set(&nbr->reachable, UIP_ND6_REACHABLE_TIME / 1000);
LOG_INFO("received a link layer ACK : ");
LOG_INFO_LLADDR((uip_lladdr_t *)dest);
LOG_INFO_(" is reachable.\n");
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
uip_ds6_nbr_entry_t *nbr_entry;
if((nbr_entry =
(uip_ds6_nbr_entry_t *)nbr_table_get_from_lladdr(uip_ds6_nbr_entries,
dest)) == NULL) {
return;
}
for(nbr = (uip_ds6_nbr_t *)list_head(nbr_entry->uip_ds6_nbrs);
nbr != NULL;
nbr = (uip_ds6_nbr_t *)list_item_next(nbr)) {
update_nbr_reachable_state_by_ack(nbr, dest);
}
#else /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
nbr = uip_ds6_nbr_ll_lookup((uip_lladdr_t *)dest);
update_nbr_reachable_state_by_ack(nbr, dest);
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
}
#endif /* UIP_DS6_LL_NUD */
}
@ -283,7 +535,7 @@ uip_ds6_link_callback(int status, int numtx)
void
uip_ds6_neighbor_periodic(void)
{
uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
uip_ds6_nbr_t *nbr = uip_ds6_nbr_head();
while(nbr != NULL) {
switch(nbr->state) {
case NBR_REACHABLE:
@ -354,7 +606,7 @@ uip_ds6_neighbor_periodic(void)
default:
break;
}
nbr = nbr_table_next(ds6_neighbors, nbr);
nbr = uip_ds6_nbr_next(nbr);
}
}
/*---------------------------------------------------------------------------*/
@ -373,7 +625,7 @@ uip_ds6_nbr_refresh_reachable_state(const uip_ipaddr_t *ipaddr)
uip_ds6_nbr_t *
uip_ds6_get_least_lifetime_neighbor(void)
{
uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors);
uip_ds6_nbr_t *nbr = uip_ds6_nbr_head();
uip_ds6_nbr_t *nbr_expiring = NULL;
while(nbr != NULL) {
if(nbr_expiring != NULL) {
@ -384,7 +636,7 @@ uip_ds6_get_least_lifetime_neighbor(void)
} else {
nbr_expiring = nbr;
}
nbr = nbr_table_next(ds6_neighbors, nbr);
nbr = uip_ds6_nbr_next(nbr);
}
return nbr_expiring;
}

View File

@ -54,6 +54,10 @@
#if UIP_CONF_IPV6_QUEUE_PKT
#include "net/ipv6/uip-packetqueue.h"
#endif /*UIP_CONF_QUEUE_PKT */
#if UIP_DS6_NBR_CONF_MULTI_IPV6_ADDRS
#include "lib/assert.h"
#include "lib/list.h"
#endif
/*--------------------------------------------------*/
/** \brief Possible states for the nbr cache entries */
@ -63,8 +67,32 @@
#define NBR_DELAY 3
#define NBR_PROBE 4
#ifdef UIP_DS6_NBR_CONF_MULTI_IPV6_ADDRS
#define UIP_DS6_NBR_MULTI_IPV6_ADDRS UIP_DS6_NBR_CONF_MULTI_IPV6_ADDRS
#else
#define UIP_DS6_NBR_MULTI_IPV6_ADDRS 0
#endif /* UIP_DS6_NBR_CONF_MULTI_IPV6_ADDRS */
#ifdef UIP_DS6_NBR_CONF_MAX_NEIGHBOR_CACHES
#define UIP_DS6_NBR_MAX_NEIGHBOR_CACHES UIP_DS6_NBR_CONF_MAX_NEIGHBOR_CACHES
#else
#define UIP_DS6_NBR_MAX_NEIGHBOR_CACHES NBR_TABLE_MAX_NEIGHBORS
#endif /* UIP_DS6_NBR_CONF_MAX_NEIGHBOR_CACHES */
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
/** \brief An nbr_table entry for neighbor caches */
typedef struct {
LIST_STRUCT(uip_ds6_nbrs);
} uip_ds6_nbr_entry_t;
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
/** \brief An entry in the nbr cache */
typedef struct uip_ds6_nbr {
#if UIP_DS6_NBR_MULTI_IPV6_ADDRS
struct uip_ds6_nbr *next;
uip_ds6_nbr_entry_t *nbr_entry;
#endif /* UIP_DS6_NBR_MULTI_IPV6_ADDRS */
uip_ipaddr_t ipaddr;
uint8_t isrouter;
uint8_t state;