1
0
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:
Cenk Gündoğan 2017-10-06 15:42:39 +02:00 committed by GitHub
commit 080590f587
10 changed files with 796 additions and 9 deletions

View File

@ -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" {

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

View File

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

View File

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

View 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("");
}
/** @} */

View File

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

View File

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

View 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;
}

View File

@ -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());
}

View File

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