mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #7222 from miri64/gnrc_ipv6_nib/feat/pl-component
gnrc_ipv6_nib: add prefix list component
This commit is contained in:
commit
080590f587
@ -23,6 +23,7 @@
|
||||
#define NET_GNRC_IPV6_NIB_H
|
||||
|
||||
#include "net/gnrc/ipv6/nib/nc.h"
|
||||
#include "net/gnrc/ipv6/nib/pl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
137
sys/include/net/gnrc/ipv6/nib/pl.h
Normal file
137
sys/include/net/gnrc/ipv6/nib/pl.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_ipv6_nib_pl Prefix list
|
||||
* @ingroup net_gnrc_ipv6_nib
|
||||
* @brief Prefix list component of neighbor information base
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Prefix list defintions
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef NET_GNRC_IPV6_NIB_PL_H
|
||||
#define NET_GNRC_IPV6_NIB_PL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "net/ipv6/addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Prefix list entry view on NIB
|
||||
*/
|
||||
typedef struct {
|
||||
ipv6_addr_t pfx; /**< prefix */
|
||||
uint8_t pfx_len; /**< length of gnrc_ipv6_nib_pl_t::pfx in bits */
|
||||
uint16_t iface; /**< interface gnrc_ipv6_nib_pl_t::pfx is assigned
|
||||
* to */
|
||||
uint32_t valid_until; /**< timestamp (in ms) until which the prefix is
|
||||
valid */
|
||||
uint32_t pref_until; /**< timestamp (in ms) until which the prefix is
|
||||
preferred */
|
||||
} gnrc_ipv6_nib_pl_t;
|
||||
|
||||
/**
|
||||
* @brief Adds (or updates) prefix to NIB
|
||||
*
|
||||
* @pre `(pfx != NULL)`
|
||||
*
|
||||
* @param[in] iface Interface @p pfx is valid on.
|
||||
* @param[in] pfx The prefix. May not be a link-local prefix or a
|
||||
* multicast address and its first @p pfx_len bits
|
||||
* may not be 0.
|
||||
* @param[in] pfx_len Length of @p pfx in bits.
|
||||
* Condition @p pfx_len > 0 must hold.
|
||||
* @param[in] valid_ltime Lifetime (in ms) until prefix expires from now.
|
||||
* UINT32_MAX for infinite lifetime. Addresses with
|
||||
* expired prefixes are removed from @p iface.
|
||||
* @param[in] pref_ltime Lifetime (in ms) until prefix deprecates from now.
|
||||
* UINT32_MAX for infinite lifetime. Addresses with
|
||||
* deprecated prefixes should not be used for new
|
||||
* communication. Only applications with difficulty
|
||||
* changing to another address without service
|
||||
* disruption should use deprecated addresses. May not
|
||||
* be greater then @p valid_ltime.
|
||||
*
|
||||
* @return 0, on success.
|
||||
* @return -EINVAL, if @p pfx was fe80::` or multicast,
|
||||
* @p pfx_len was == 0, the first @p pfx_len bits of @ pfx were 0,
|
||||
* or if pref_ltime > valid_ltime.
|
||||
* @return -ENOMEM, if no space was left in the prefix list.
|
||||
*/
|
||||
int gnrc_ipv6_nib_pl_set(unsigned iface,
|
||||
const ipv6_addr_t *pfx, unsigned pfx_len,
|
||||
uint32_t valid_ltime, uint32_t pref_ltime);
|
||||
|
||||
/**
|
||||
* @brief Deletes prefix from NIB
|
||||
*
|
||||
* @pre `pfx != NULL`
|
||||
*
|
||||
* @param[in] iface The interface @p pfx is expected to be on (0 for any).
|
||||
* @param[in] pfx The prefix to be removed.
|
||||
* @param[in] pfx_len Length of @p pfx in bits.
|
||||
*/
|
||||
void gnrc_ipv6_nib_pl_del(unsigned iface,
|
||||
const ipv6_addr_t *pfx, unsigned pfx_len);
|
||||
|
||||
/**
|
||||
* @brief Iterates over all prefix list entries in the NIB.
|
||||
*
|
||||
* @pre `(state != NULL) && (ple != NULL)`
|
||||
*
|
||||
* @param[in] iface Restrict iteration to entries on this interface.
|
||||
* 0 for any interface.
|
||||
* @param[in,out] state Iteration state of the prefix list. Must point to NULL
|
||||
* pointer to start iteration
|
||||
* @param[out] ple The next prefix list entry.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
|
||||
* #include "net/gnrc/ipv6/nib/pl.h"
|
||||
*
|
||||
* int main(void) {
|
||||
* void *state = NULL;
|
||||
* gnrc_ipv6_nib_pl_t ple;
|
||||
*
|
||||
* puts("My prefixes:");
|
||||
* while (gnrc_ipv6_nib_pl_iter(0, &state, &ple)) {
|
||||
* gnrc_ipv6_nib_pl_print(&ple);
|
||||
* }
|
||||
* return 0;
|
||||
* }
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* @return true, if iteration can be continued.
|
||||
* @return false, if @p ple is the last prefix list ple in the NIB.
|
||||
*/
|
||||
bool gnrc_ipv6_nib_pl_iter(unsigned iface, void **state,
|
||||
gnrc_ipv6_nib_pl_t *ple);
|
||||
|
||||
/**
|
||||
* @brief Prints a prefix list entry
|
||||
*
|
||||
* @pre `ple != NULL`
|
||||
*
|
||||
* @param[in] ple A prefix list entry
|
||||
*/
|
||||
void gnrc_ipv6_nib_pl_print(gnrc_ipv6_nib_pl_t *ple);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_GNRC_IPV6_NIB_PL_H */
|
||||
/** @} */
|
@ -483,6 +483,41 @@ _nib_offl_entry_t *_nib_offl_iter(const _nib_offl_entry_t *last)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_nib_offl_entry_t *_nib_pl_add(unsigned iface,
|
||||
const ipv6_addr_t *pfx,
|
||||
unsigned pfx_len,
|
||||
uint32_t valid_ltime,
|
||||
uint32_t pref_ltime)
|
||||
{
|
||||
_nib_offl_entry_t *dst = _nib_offl_add(NULL, iface, pfx, pfx_len, _PL);
|
||||
|
||||
if (dst == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
assert(valid_ltime >= pref_ltime);
|
||||
if ((valid_ltime != UINT32_MAX) || (pref_ltime != UINT32_MAX)) {
|
||||
uint32_t now = (xtimer_now_usec64() / US_PER_MS) & UINT32_MAX;
|
||||
if (pref_ltime != UINT32_MAX) {
|
||||
_evtimer_add(dst, GNRC_IPV6_NIB_PFX_TIMEOUT, &dst->pfx_timeout,
|
||||
pref_ltime);
|
||||
if (((pref_ltime + now) == UINT32_MAX) && (now != 0)) {
|
||||
pref_ltime++;
|
||||
}
|
||||
pref_ltime += now;
|
||||
}
|
||||
if (valid_ltime != UINT32_MAX) {
|
||||
/* prevent valid_ltime from becoming UINT32_MAX */
|
||||
if ((valid_ltime + now) == UINT32_MAX) {
|
||||
valid_ltime++;
|
||||
}
|
||||
valid_ltime += now;
|
||||
}
|
||||
}
|
||||
dst->valid_until = valid_ltime;
|
||||
dst->pref_until = pref_ltime;
|
||||
return dst;
|
||||
}
|
||||
|
||||
_nib_iface_t *_nib_iface_get(unsigned iface)
|
||||
{
|
||||
_nib_iface_t *ni = NULL;
|
||||
|
@ -165,8 +165,16 @@ typedef struct {
|
||||
ipv6_addr_t pfx; /**< prefix to the destination */
|
||||
unsigned pfx_len; /**< prefix-length in bits of
|
||||
* _nib_onl_entry_t::pfx */
|
||||
/**
|
||||
* @brief Event for @ref GNRC_IPV6_NIB_PFX_TIMEOUT
|
||||
*/
|
||||
evtimer_msg_event_t pfx_timeout;
|
||||
uint8_t mode; /**< [mode](@ref net_gnrc_ipv6_nib_mode) of the
|
||||
* off-link entry */
|
||||
uint32_t valid_until; /**< timestamp (in ms) until which the prefix
|
||||
valid (UINT32_MAX means forever) */
|
||||
uint32_t pref_until; /**< timestamp (in ms) until which the prefix
|
||||
preferred (UINT32_MAX means forever) */
|
||||
} _nib_offl_entry_t;
|
||||
|
||||
/**
|
||||
@ -565,6 +573,7 @@ static inline void _nib_dc_remove(_nib_offl_entry_t *nib_offl)
|
||||
*
|
||||
* @pre `(next_hop != NULL)`
|
||||
* @pre `(pfx != NULL) && (pfx != "::") && (pfx_len != 0) && (pfx_len <= 128)`
|
||||
* @pre `(pref_ltime <= valid_ltime)`
|
||||
*
|
||||
* @param[in] iface The interface to the prefix is added to.
|
||||
* @param[in] pfx The IPv6 prefix or address of the destination.
|
||||
@ -576,12 +585,11 @@ static inline void _nib_dc_remove(_nib_offl_entry_t *nib_offl)
|
||||
* @p pfx.
|
||||
* @return NULL, if no space is left.
|
||||
*/
|
||||
static inline _nib_offl_entry_t *_nib_pl_add(unsigned iface,
|
||||
const ipv6_addr_t *pfx,
|
||||
unsigned pfx_len)
|
||||
{
|
||||
return _nib_offl_add(NULL, iface, pfx, pfx_len, _PL);
|
||||
}
|
||||
_nib_offl_entry_t *_nib_pl_add(unsigned iface,
|
||||
const ipv6_addr_t *pfx,
|
||||
unsigned pfx_len,
|
||||
uint32_t valid_ltime,
|
||||
uint32_t pref_ltime);
|
||||
|
||||
/**
|
||||
* @brief Removes a prefix list entry
|
||||
@ -592,6 +600,7 @@ static inline _nib_offl_entry_t *_nib_pl_add(unsigned iface,
|
||||
*/
|
||||
static inline void _nib_pl_remove(_nib_offl_entry_t *nib_offl)
|
||||
{
|
||||
evtimer_del(&_nib_evtimer, &nib_offl->pfx_timeout.event);
|
||||
_nib_offl_remove(nib_offl, _PL);
|
||||
}
|
||||
|
||||
|
120
sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c
Normal file
120
sys/net/gnrc/network_layer/ipv6/nib/nib_pl.c
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "net/gnrc/ipv6/nib/pl.h"
|
||||
#include "timex.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#include "_nib-internal.h"
|
||||
|
||||
int gnrc_ipv6_nib_pl_set(unsigned iface,
|
||||
const ipv6_addr_t *pfx, unsigned pfx_len,
|
||||
uint32_t valid_ltime, uint32_t pref_ltime)
|
||||
{
|
||||
int res = 0;
|
||||
_nib_offl_entry_t *dst;
|
||||
ipv6_addr_t tmp = IPV6_ADDR_UNSPECIFIED;
|
||||
|
||||
assert((pfx != NULL));
|
||||
if (pfx_len > IPV6_ADDR_BIT_LEN) {
|
||||
pfx_len = IPV6_ADDR_BIT_LEN;
|
||||
}
|
||||
ipv6_addr_init_prefix(&tmp, pfx, pfx_len);
|
||||
/* pfx_len == 0 implicitly checked, since this leaves tmp unspecified */
|
||||
if (ipv6_addr_is_unspecified(&tmp) || ipv6_addr_is_link_local(pfx) ||
|
||||
ipv6_addr_is_multicast(pfx) || (pref_ltime > valid_ltime)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock(&_nib_mutex);
|
||||
dst = _nib_pl_add(iface, pfx, pfx_len, valid_ltime,
|
||||
pref_ltime);
|
||||
if (dst == NULL) {
|
||||
res = -ENOMEM;
|
||||
}
|
||||
mutex_unlock(&_nib_mutex);
|
||||
/* TODO: send RA with PIO, if iface is allowed to send RAs */
|
||||
return res;
|
||||
}
|
||||
|
||||
void gnrc_ipv6_nib_pl_del(unsigned iface,
|
||||
const ipv6_addr_t *pfx, unsigned pfx_len)
|
||||
{
|
||||
_nib_offl_entry_t *dst = NULL;
|
||||
|
||||
assert(pfx != NULL);
|
||||
mutex_lock(&_nib_mutex);
|
||||
while ((dst = _nib_offl_iter(dst)) != NULL) {
|
||||
assert(dst->next_hop != NULL);
|
||||
if ((pfx_len == dst->pfx_len) &&
|
||||
((iface == 0) || (iface == _nib_onl_get_if(dst->next_hop))) &&
|
||||
(ipv6_addr_match_prefix(pfx, &dst->pfx) >= pfx_len)) {
|
||||
_nib_pl_remove(dst);
|
||||
mutex_unlock(&_nib_mutex);
|
||||
/* TODO: send RA with PIO, if iface is allowed to send RAs */
|
||||
return;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&_nib_mutex);
|
||||
}
|
||||
|
||||
bool gnrc_ipv6_nib_pl_iter(unsigned iface, void **state,
|
||||
gnrc_ipv6_nib_pl_t *entry)
|
||||
{
|
||||
_nib_offl_entry_t *dst = *state;
|
||||
|
||||
mutex_lock(&_nib_mutex);
|
||||
while ((dst = _nib_offl_iter(dst)) != NULL) {
|
||||
const _nib_onl_entry_t *node = dst->next_hop;
|
||||
assert(node != NULL);
|
||||
if ((dst->mode & _PL) &&
|
||||
((iface == 0) || (_nib_onl_get_if(node) == iface))) {
|
||||
entry->pfx_len = dst->pfx_len;
|
||||
ipv6_addr_set_unspecified(&entry->pfx);
|
||||
ipv6_addr_init_prefix(&entry->pfx, &dst->pfx, dst->pfx_len);
|
||||
entry->iface = _nib_onl_get_if(node);
|
||||
entry->valid_until = dst->valid_until;
|
||||
entry->pref_until = dst->pref_until;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&_nib_mutex);
|
||||
*state = dst;
|
||||
return (*state != NULL);
|
||||
}
|
||||
|
||||
void gnrc_ipv6_nib_pl_print(gnrc_ipv6_nib_pl_t *entry)
|
||||
{
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
ipv6_addr_t pfx = IPV6_ADDR_UNSPECIFIED;
|
||||
uint32_t now = ((xtimer_now_usec64() / US_PER_MS)) & UINT32_MAX;
|
||||
|
||||
ipv6_addr_init_prefix(&pfx, &entry->pfx, entry->pfx_len);
|
||||
printf("%s/%u ", ipv6_addr_to_str(addr_str, &pfx, sizeof(addr_str)),
|
||||
entry->pfx_len);
|
||||
printf("dev #%u ", entry->iface);
|
||||
if (entry->valid_until < UINT32_MAX) {
|
||||
printf(" expires %" PRIu32 "sec", (entry->valid_until - now) / MS_PER_SEC);
|
||||
}
|
||||
if (entry->pref_until < UINT32_MAX) {
|
||||
printf(" deprecates %" PRIu32 "sec", (entry->pref_until - now) / MS_PER_SEC);
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
/** @} */
|
@ -21,6 +21,7 @@
|
||||
|
||||
static void _usage(char **argv);
|
||||
static int _nib_neigh(int argc, char **argv);
|
||||
static int _nib_prefix(int argc, char **argv);
|
||||
|
||||
int _gnrc_ipv6_nib(int argc, char **argv)
|
||||
{
|
||||
@ -33,6 +34,9 @@ int _gnrc_ipv6_nib(int argc, char **argv)
|
||||
else if (strcmp(argv[1], "neigh") == 0) {
|
||||
res = _nib_neigh(argc, argv);
|
||||
}
|
||||
else if (strcmp(argv[1], "prefix") == 0) {
|
||||
res = _nib_prefix(argc, argv);
|
||||
}
|
||||
else {
|
||||
_usage(argv);
|
||||
}
|
||||
@ -41,7 +45,7 @@ int _gnrc_ipv6_nib(int argc, char **argv)
|
||||
|
||||
static void _usage(char **argv)
|
||||
{
|
||||
printf("usage: %s {neigh|help} ...\n", argv[0]);
|
||||
printf("usage: %s {neigh|prefix|help} ...\n", argv[0]);
|
||||
}
|
||||
|
||||
static void _usage_nib_neigh(char **argv)
|
||||
@ -52,6 +56,15 @@ static void _usage_nib_neigh(char **argv)
|
||||
printf(" %s %s show <ipv6 addr>\n", argv[0], argv[1]);
|
||||
}
|
||||
|
||||
static void _usage_nib_prefix(char **argv)
|
||||
{
|
||||
printf("usage: %s %s [show|add|del|help]\n", argv[0], argv[1]);
|
||||
printf(" %s %s add <iface> <prefix>[/<prefix_len>] [<valid in ms>] [<pref in ms>]\n",
|
||||
argv[0], argv[1]);
|
||||
printf(" %s %s del <iface> <prefix>[/<prefix_len>]\n", argv[0], argv[1]);
|
||||
printf(" %s %s show <iface>\n", argv[0], argv[1]);
|
||||
}
|
||||
|
||||
static int _nib_neigh(int argc, char **argv)
|
||||
{
|
||||
if ((argc == 2) || (strcmp(argv[2], "show") == 0)) {
|
||||
@ -103,4 +116,57 @@ static int _nib_neigh(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nib_prefix(int argc, char **argv)
|
||||
{
|
||||
if ((argc == 2) || (strcmp(argv[2], "show") == 0)) {
|
||||
gnrc_ipv6_nib_pl_t entry;
|
||||
void *state = NULL;
|
||||
unsigned iface = 0U;
|
||||
|
||||
if (argc > 3) {
|
||||
iface = atoi(argv[3]);
|
||||
}
|
||||
while (gnrc_ipv6_nib_pl_iter(iface, &state, &entry)) {
|
||||
gnrc_ipv6_nib_pl_print(&entry);
|
||||
}
|
||||
}
|
||||
else if ((argc > 2) && (strcmp(argv[2], "help") == 0)) {
|
||||
_usage_nib_prefix(argv);
|
||||
}
|
||||
else if ((argc > 4) && (strcmp(argv[2], "add") == 0)) {
|
||||
ipv6_addr_t pfx;
|
||||
unsigned iface = atoi(argv[3]);
|
||||
unsigned pfx_len = ipv6_addr_split_prefix(argv[4]);
|
||||
unsigned valid_ltime = UINT32_MAX, pref_ltime = UINT32_MAX;
|
||||
|
||||
if (ipv6_addr_from_str(&pfx, argv[4]) == NULL) {
|
||||
_usage_nib_prefix(argv);
|
||||
return 1;
|
||||
}
|
||||
if (argc > 5) {
|
||||
valid_ltime = atoi(argv[5]);
|
||||
}
|
||||
if (argc > 6) {
|
||||
pref_ltime = atoi(argv[6]);
|
||||
}
|
||||
gnrc_ipv6_nib_pl_set(iface, &pfx, pfx_len, valid_ltime, pref_ltime);
|
||||
}
|
||||
else if ((argc > 4) && (strcmp(argv[2], "del") == 0)) {
|
||||
ipv6_addr_t pfx;
|
||||
unsigned iface = atoi(argv[3]);
|
||||
unsigned pfx_len = ipv6_addr_split_prefix(argv[4]);
|
||||
|
||||
if (ipv6_addr_from_str(&pfx, argv[4]) == NULL) {
|
||||
_usage_nib_prefix(argv);
|
||||
return 1;
|
||||
}
|
||||
gnrc_ipv6_nib_pl_del(iface, &pfx, pfx_len);
|
||||
}
|
||||
else {
|
||||
_usage_nib_prefix(argv);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
@ -1647,13 +1647,16 @@ static void test_nib_pl_add__success(void)
|
||||
_nib_offl_entry_t *dst;
|
||||
static const ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
|
||||
TEST_ASSERT_NOT_NULL((dst = _nib_pl_add(IFACE, &pfx, GLOBAL_PREFIX_LEN)));
|
||||
TEST_ASSERT_NOT_NULL((dst = _nib_pl_add(IFACE, &pfx, GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX, UINT32_MAX)));
|
||||
TEST_ASSERT(dst->mode & _PL);
|
||||
TEST_ASSERT_EQUAL_INT(GLOBAL_PREFIX_LEN, dst->pfx_len);
|
||||
TEST_ASSERT(GLOBAL_PREFIX_LEN <= ipv6_addr_match_prefix(&pfx, &dst->pfx));
|
||||
TEST_ASSERT_NOT_NULL(dst->next_hop);
|
||||
TEST_ASSERT_EQUAL_INT(_DST, dst->next_hop->mode);
|
||||
TEST_ASSERT_EQUAL_INT(IFACE, _nib_onl_get_if(dst->next_hop));
|
||||
TEST_ASSERT_EQUAL_INT(UINT32_MAX, dst->valid_until);
|
||||
TEST_ASSERT_EQUAL_INT(UINT32_MAX, dst->pref_until);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1666,7 +1669,8 @@ static void test_nib_pl_remove(void)
|
||||
_nib_offl_entry_t *dst;
|
||||
static const ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
|
||||
TEST_ASSERT_NOT_NULL((dst = _nib_pl_add(IFACE, &pfx, GLOBAL_PREFIX_LEN)));
|
||||
TEST_ASSERT_NOT_NULL((dst = _nib_pl_add(IFACE, &pfx, GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX, UINT32_MAX)));
|
||||
_nib_pl_remove(dst);
|
||||
TEST_ASSERT_NULL(_nib_offl_iter(NULL));
|
||||
}
|
||||
|
407
tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-pl.c
Normal file
407
tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-pl.c
Normal file
@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "net/ipv6/addr.h"
|
||||
#include "net/gnrc/ipv6/nib.h"
|
||||
#include "net/gnrc/ipv6/nib/pl.h"
|
||||
|
||||
#include "_nib-internal.h"
|
||||
|
||||
#include "unittests-constants.h"
|
||||
|
||||
#include "tests-gnrc_ipv6_nib.h"
|
||||
|
||||
#define LINK_LOCAL_PREFIX { 0xfe, 0x08, 0, 0, 0, 0, 0, 0 }
|
||||
#define GLOBAL_PREFIX { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0 }
|
||||
#define L2ADDR { 0x90, 0xd5, 0x8e, 0x8c, 0x92, 0x43, 0x73, 0x5c }
|
||||
#define GLOBAL_PREFIX_LEN (30)
|
||||
#define IFACE (6)
|
||||
|
||||
static void set_up(void)
|
||||
{
|
||||
/* TODO: add if #6988 gets merged */
|
||||
/* evtimer_event_t *tmp; */
|
||||
|
||||
/* for (evtimer_event_t *ptr = _nib_evtimer.events; */
|
||||
/* (ptr != NULL) && (tmp = (ptr->next), 1); */
|
||||
/* ptr = tmp) { */
|
||||
/* evtimer_del((evtimer_t *)(&_nib_evtimer), ptr); */
|
||||
/* } */
|
||||
_nib_init();
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to create a prefix list entry with the unspecified address (::) as
|
||||
* prefix.
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() returns -EINVAL
|
||||
*/
|
||||
static void test_nib_pl_set__EINVAL_unspec_addr(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, gnrc_ipv6_nib_pl_set(IFACE,
|
||||
&ipv6_addr_unspecified,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to create a prefix list entry with a link-local prefix (fe80::) as
|
||||
* prefix.
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() returns -EINVAL
|
||||
*/
|
||||
static void test_nib_pl_set__EINVAL_link_local(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, gnrc_ipv6_nib_pl_set(IFACE,
|
||||
&ipv6_addr_link_local_prefix,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to create a prefix list entry with the multicast address as
|
||||
* prefix.
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() returns -EINVAL
|
||||
*/
|
||||
static void test_nib_pl_set__EINVAL_mc_addr(void)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, gnrc_ipv6_nib_pl_set(IFACE,
|
||||
&ipv6_addr_all_nodes_link_local,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to create multiple prefix list entries with prefix length 0 and > 128.
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() always returns -EINVAL
|
||||
*/
|
||||
static void test_nib_pl_set__EINVAL_pfx_len(void)
|
||||
{
|
||||
static const ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, gnrc_ipv6_nib_pl_set(IFACE, &pfx, 0,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX));
|
||||
}
|
||||
|
||||
#if GNRC_IPV6_NIB_NUMOF < GNRC_IPV6_NIB_OFFL_NUMOF
|
||||
#define MAX_NUMOF (GNRC_IPV6_NIB_NUMOF)
|
||||
#else /* GNRC_IPV6_NIB_NUMOF < GNRC_IPV6_NIB_OFFL_NUMOF */
|
||||
#define MAX_NUMOF (GNRC_IPV6_NIB_OFFL_NUMOF)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF prefix list entries with different interfaces and then
|
||||
* tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_pl_set__ENOMEM_diff_iface(void)
|
||||
{
|
||||
static const ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(iface, &pfx,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
iface++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_pl_set(iface, &pfx,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates GNRC_IPV6_NIB_OFFL_NUMOF prefix list entries with different prefix of
|
||||
* the same length and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_pl_set__ENOMEM_diff_pfx(void)
|
||||
{
|
||||
ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
for (unsigned i = 0; i < GNRC_IPV6_NIB_OFFL_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(IFACE, &pfx,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
pfx.u16[0].u16++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_pl_set(IFACE, &pfx,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates GNRC_IPV6_NIB_OFFL_NUMOF prefix list entries with different prefix of
|
||||
* the same length and different interfaces and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_pl_set__ENOMEM_diff_iface_pfx(void)
|
||||
{
|
||||
ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(iface, &pfx,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
iface++;
|
||||
pfx.u16[0].u16++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_pl_set(iface, &pfx,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates GNRC_IPV6_NIB_OFFL_NUMOF prefix list entries with prefixes of
|
||||
* different length and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_pl_set__ENOMEM_diff_pfx_len(void)
|
||||
{
|
||||
static const ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned pfx_len = GLOBAL_PREFIX_LEN;
|
||||
|
||||
for (unsigned i = 0; i < GNRC_IPV6_NIB_OFFL_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(IFACE, &pfx, pfx_len,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
pfx_len--;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_pl_set(IFACE, &pfx, pfx_len,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF prefix list entries with prefixes of different length and
|
||||
* different interfaces and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_pl_set__ENOMEM_diff_iface_pfx_len(void)
|
||||
{
|
||||
static const ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned pfx_len = GLOBAL_PREFIX_LEN, iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(iface, &pfx, pfx_len,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
pfx_len--;
|
||||
iface++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_pl_set(iface, &pfx, pfx_len,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates GNRC_IPV6_NIB_OFFL_NUMOF prefix list entries with different prefixes
|
||||
* and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_pl_set__ENOMEM_diff_pfx_pfx_len(void)
|
||||
{
|
||||
ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned pfx_len = GLOBAL_PREFIX_LEN;
|
||||
|
||||
for (unsigned i = 0; i < GNRC_IPV6_NIB_OFFL_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(IFACE, &pfx, pfx_len,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
pfx_len--;
|
||||
pfx.u16[0].u16++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_pl_set(IFACE, &pfx, pfx_len,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF prefix list entries with different prefixes and different
|
||||
* interfaces then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_pl_set() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_pl_set__ENOMEM_diff_iface_pfx_pfx_len(void)
|
||||
{
|
||||
ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned pfx_len = GLOBAL_PREFIX_LEN, iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(iface, &pfx, pfx_len,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
pfx_len--;
|
||||
pfx.u16[0].u16++;
|
||||
iface++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_pl_set(iface, &pfx, pfx_len,
|
||||
UINT32_MAX,
|
||||
UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF prefix list entries with different prefixes and different
|
||||
* interfaces and then tries to add another equal to the last.
|
||||
* Expected result: should return not NULL (the last)
|
||||
*/
|
||||
static void test_nib_pl_set__success_duplicate(void)
|
||||
{
|
||||
ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned pfx_len = GLOBAL_PREFIX_LEN, iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
pfx_len--;
|
||||
pfx.u16[0].u16++;
|
||||
iface++;
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(iface, &pfx, pfx_len,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(iface, &pfx, pfx_len,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a prefix list entry then creates it again with a different valid and
|
||||
* preferred lifetime.
|
||||
* Expected result: should be able to be created and the lifetimes should have
|
||||
* been changed
|
||||
*/
|
||||
static void test_nib_pl_set__success_change(void)
|
||||
{
|
||||
gnrc_ipv6_nib_pl_t ple;
|
||||
void *iter_state = NULL;
|
||||
static const ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(IFACE, &pfx,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(IFACE, &pfx,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
TEST_UINT32,
|
||||
TEST_UINT32 - TEST_UINT8));
|
||||
TEST_ASSERT(gnrc_ipv6_nib_pl_iter(0, &iter_state, &ple));
|
||||
TEST_ASSERT(ple.valid_until != UINT32_MAX);
|
||||
TEST_ASSERT(ple.pref_until != UINT32_MAX);
|
||||
TEST_ASSERT(!gnrc_ipv6_nib_pl_iter(0, &iter_state, &ple));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a prefix list entry then creates it again with a different valid and
|
||||
* preferred lifetime.
|
||||
* Expected result: a new entry should exist and contain the given prefix,
|
||||
* interface, and lifetimes
|
||||
*/
|
||||
static void test_nib_pl_set__success(void)
|
||||
{
|
||||
gnrc_ipv6_nib_pl_t ple;
|
||||
void *iter_state = NULL;
|
||||
static const ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(IFACE, &pfx,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
TEST_ASSERT(gnrc_ipv6_nib_pl_iter(0, &iter_state, &ple));
|
||||
TEST_ASSERT(ipv6_addr_match_prefix(&ple.pfx, &pfx) >= GLOBAL_PREFIX_LEN);
|
||||
TEST_ASSERT_EQUAL_INT(GLOBAL_PREFIX_LEN, ple.pfx_len);
|
||||
TEST_ASSERT_EQUAL_INT(IFACE, ple.iface);
|
||||
TEST_ASSERT_EQUAL_INT(UINT32_MAX, ple.valid_until);
|
||||
TEST_ASSERT_EQUAL_INT(UINT32_MAX, ple.pref_until);
|
||||
TEST_ASSERT(!gnrc_ipv6_nib_pl_iter(0, &iter_state, &ple));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF prefix list entries with different prefix and interfaces
|
||||
* and then tries to delete one with yet another prefix and interface.
|
||||
* Expected result: There should be still GNRC_IPV6_NIB_NUMOF entries in the
|
||||
* neigbor cache
|
||||
*/
|
||||
static void test_nib_pl_del__unknown(void)
|
||||
{
|
||||
void *iter_state = NULL;
|
||||
ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
gnrc_ipv6_nib_pl_t ple;
|
||||
unsigned pfx_len = GLOBAL_PREFIX_LEN, iface = IFACE, count = 0;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(iface, &pfx, pfx_len,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
pfx_len--;
|
||||
pfx.u16[0].u16++;
|
||||
iface++;
|
||||
}
|
||||
gnrc_ipv6_nib_pl_del(iface, &pfx, pfx_len);
|
||||
while (gnrc_ipv6_nib_pl_iter(0, &iter_state, &ple)) {
|
||||
count++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(MAX_NUMOF, count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a prefix entry and removes it.
|
||||
* Expected result: prefix entry should be empty
|
||||
*/
|
||||
static void test_nib_pl_del__success(void)
|
||||
{
|
||||
void *iter_state = NULL;
|
||||
ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
gnrc_ipv6_nib_pl_t ple;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_pl_set(IFACE, &pfx, GLOBAL_PREFIX_LEN,
|
||||
UINT32_MAX, UINT32_MAX));
|
||||
gnrc_ipv6_nib_pl_del(IFACE, &pfx, GLOBAL_PREFIX_LEN);
|
||||
TEST_ASSERT(!gnrc_ipv6_nib_pl_iter(0, &iter_state, &ple));
|
||||
}
|
||||
|
||||
Test *tests_gnrc_ipv6_nib_pl_tests(void)
|
||||
{
|
||||
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||
new_TestFixture(test_nib_pl_set__EINVAL_unspec_addr),
|
||||
new_TestFixture(test_nib_pl_set__EINVAL_link_local),
|
||||
new_TestFixture(test_nib_pl_set__EINVAL_mc_addr),
|
||||
new_TestFixture(test_nib_pl_set__EINVAL_pfx_len),
|
||||
new_TestFixture(test_nib_pl_set__ENOMEM_diff_pfx),
|
||||
new_TestFixture(test_nib_pl_set__ENOMEM_diff_iface),
|
||||
new_TestFixture(test_nib_pl_set__ENOMEM_diff_iface_pfx),
|
||||
new_TestFixture(test_nib_pl_set__ENOMEM_diff_pfx_len),
|
||||
new_TestFixture(test_nib_pl_set__ENOMEM_diff_iface_pfx_len),
|
||||
new_TestFixture(test_nib_pl_set__ENOMEM_diff_pfx_pfx_len),
|
||||
new_TestFixture(test_nib_pl_set__ENOMEM_diff_iface_pfx_pfx_len),
|
||||
new_TestFixture(test_nib_pl_set__success_duplicate),
|
||||
new_TestFixture(test_nib_pl_set__success_change),
|
||||
new_TestFixture(test_nib_pl_set__success),
|
||||
new_TestFixture(test_nib_pl_del__unknown),
|
||||
new_TestFixture(test_nib_pl_del__success),
|
||||
/* gnrc_ipv6_nib_pl_iter() is tested during all the tests above */
|
||||
};
|
||||
|
||||
EMB_UNIT_TESTCALLER(tests, set_up, NULL,
|
||||
fixtures);
|
||||
|
||||
return (Test *)&tests;
|
||||
}
|
@ -19,4 +19,5 @@ void tests_gnrc_ipv6_nib(void)
|
||||
{
|
||||
TESTS_RUN(tests_gnrc_ipv6_nib_internal_tests());
|
||||
TESTS_RUN(tests_gnrc_ipv6_nib_nc_tests());
|
||||
TESTS_RUN(tests_gnrc_ipv6_nib_pl_tests());
|
||||
}
|
||||
|
@ -43,6 +43,13 @@ Test *tests_gnrc_ipv6_nib_internal_tests(void);
|
||||
*/
|
||||
Test *tests_gnrc_ipv6_nib_nc_tests(void);
|
||||
|
||||
/**
|
||||
* @brief Generates tests for prefix list view
|
||||
*
|
||||
* @return embUnit tests if successful, NULL if not.
|
||||
*/
|
||||
Test *tests_gnrc_ipv6_nib_pl_tests(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user