From 0b2bc25ee038bdb24e930bab6d25e6e825a16c27 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Wed, 28 Jun 2017 19:18:48 +0200 Subject: [PATCH 1/2] gnrc_ipv6_nib: provide component to handle ABRO --- sys/include/net/gnrc/ipv6/nib.h | 1 + sys/include/net/gnrc/ipv6/nib/abr.h | 55 +++++++ sys/include/net/gnrc/ipv6/nib/conf.h | 9 ++ .../network_layer/ipv6/nib/_nib-internal.c | 139 ++++++++++++++++++ .../network_layer/ipv6/nib/_nib-internal.h | 88 ++++++++++- sys/net/gnrc/network_layer/ipv6/nib/nib_abr.c | 57 +++++++ 6 files changed, 344 insertions(+), 5 deletions(-) create mode 100644 sys/include/net/gnrc/ipv6/nib/abr.h create mode 100644 sys/net/gnrc/network_layer/ipv6/nib/nib_abr.c diff --git a/sys/include/net/gnrc/ipv6/nib.h b/sys/include/net/gnrc/ipv6/nib.h index 00796e7fd4..3a4db2763f 100644 --- a/sys/include/net/gnrc/ipv6/nib.h +++ b/sys/include/net/gnrc/ipv6/nib.h @@ -22,6 +22,7 @@ #ifndef NET_GNRC_IPV6_NIB_H #define NET_GNRC_IPV6_NIB_H +#include "net/gnrc/ipv6/nib/abr.h" #include "net/gnrc/ipv6/nib/nc.h" #include "net/gnrc/ipv6/nib/pl.h" diff --git a/sys/include/net/gnrc/ipv6/nib/abr.h b/sys/include/net/gnrc/ipv6/nib/abr.h new file mode 100644 index 0000000000..effb1ebd48 --- /dev/null +++ b/sys/include/net/gnrc/ipv6/nib/abr.h @@ -0,0 +1,55 @@ +/* + * 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_abr Authoritative border router list + * @ingroup net_gnrc_ipv6_nib + * @brief Authoritative border router list component of neighbor + * information base + * @{ + * + * @file + * @brief Authoritative border router list definitions + * + * @author Martine Lenders + */ +#ifndef NET_GNRC_IPV6_NIB_ABR_H +#define NET_GNRC_IPV6_NIB_ABR_H + +#include "net/ipv6/addr.h" +#include "net/gnrc/ipv6/nib/conf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if (GNRC_IPV6_NIB_CONF_6LBR && GNRC_IPV6_NIB_CONF_MULTIHOP_P6C) || defined(DOXYGEN) +/** + * @brief Adds the address of an authoritative border router to the NIB + * + * @param[in] addr The address of an authoritative border router. + * + * @return 0 on success. + * @return -ENOMEM, if no space is left in the neighbor cache. + */ +int gnrc_ipv6_nib_abr_add(const ipv6_addr_t *addr); + +/** + * @brief Removes an authoritative border router from the NIB + * + * @param[in] addr The address of an authoritative border router. + */ +void gnrc_ipv6_nib_abr_del(const ipv6_addr_t *addr); +#endif /* (GNRC_IPV6_NIB_CONF_6LBR && GNRC_IPV6_NIB_CONF_MULTIHOP_P6C) || defined(DOXYGEN) */ + +#ifdef __cplusplus +} +#endif + +#endif /* NET_GNRC_IPV6_NIB_ABR_H */ +/** @} */ diff --git a/sys/include/net/gnrc/ipv6/nib/conf.h b/sys/include/net/gnrc/ipv6/nib/conf.h index adacc37908..4710ede5f5 100644 --- a/sys/include/net/gnrc/ipv6/nib/conf.h +++ b/sys/include/net/gnrc/ipv6/nib/conf.h @@ -194,6 +194,15 @@ extern "C" { #define GNRC_IPV6_NIB_OFFL_NUMOF (8) #endif +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C || defined(DOXYGEN) +/** + * @brief Number of authoritative border router entries in NIB + */ +#ifndef GNRC_IPV6_NIB_ABR_NUMOF +#define GNRC_IPV6_NIB_ABR_NUMOF (1) +#endif +#endif + #ifdef __cplusplus } #endif diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c index 1593f94057..87049f245d 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c @@ -37,6 +37,10 @@ static _nib_offl_entry_t _dsts[GNRC_IPV6_NIB_OFFL_NUMOF]; static _nib_dr_entry_t _def_routers[GNRC_IPV6_NIB_DEFAULT_ROUTER_NUMOF]; static _nib_iface_t _nis[GNRC_NETIF_NUMOF]; +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C +static _nib_abr_entry_t _abrs[GNRC_IPV6_NIB_ABR_NUMOF]; +#endif + #if ENABLE_DEBUG static char addr_str[IPV6_ADDR_MAX_STR_LEN]; #endif @@ -57,6 +61,9 @@ void _nib_init(void) memset(_def_routers, 0, sizeof(_def_routers)); memset(_dsts, 0, sizeof(_dsts)); memset(_nis, 0, sizeof(_nis)); +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C + memset(_abrs, 0, sizeof(_abrs)); +#endif #endif evtimer_init_msg(&_nib_evtimer); /* TODO: load ABR information from persistent memory */ @@ -450,6 +457,13 @@ static inline bool _in_dsts(const _nib_offl_entry_t *dst) return (dst < (_dsts + GNRC_IPV6_NIB_OFFL_NUMOF)); } +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C +static inline bool _in_abrs(const _nib_abr_entry_t *abr) +{ + return (abr < (_abrs + GNRC_IPV6_NIB_ABR_NUMOF)); +} +#endif + void _nib_offl_clear(_nib_offl_entry_t *dst) { if (dst->next_hop != NULL) { @@ -483,6 +497,131 @@ _nib_offl_entry_t *_nib_offl_iter(const _nib_offl_entry_t *last) return NULL; } +void _nib_pl_remove(_nib_offl_entry_t *nib_offl) +{ + _nib_offl_remove(nib_offl, _PL); +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C + unsigned idx = nib_offl - _dsts; + if (idx < GNRC_IPV6_NIB_OFFL_NUMOF) { + for (_nib_abr_entry_t *abr = _abrs; _in_abrs(abr); abr++) { + if (bf_isset(abr->pfxs, idx)) { + DEBUG("nib: Removing prefix %s/%u ", + ipv6_addr_to_str(addr_str, &nib_offl->pfx, + sizeof(addr_str)), + nib_offl->pfx_len); + DEBUG("from border router %s\n", + ipv6_addr_to_str(addr_str, &abr->addr, sizeof(addr_str))); + bf_unset(abr->pfxs, idx); + } + } + } +#endif +} + +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C +_nib_abr_entry_t *_nib_abr_add(const ipv6_addr_t *addr) +{ + _nib_abr_entry_t *abr = NULL; + + assert(addr != NULL); + DEBUG("nib: Allocating authoritative border router entry (addr = %s)\n", + ipv6_addr_to_str(addr_str, addr, sizeof(addr_str))); + for (unsigned i = 0; i < GNRC_IPV6_NIB_ABR_NUMOF; i++) { + _nib_abr_entry_t *tmp = &_abrs[i]; + + if (ipv6_addr_equal(addr, &tmp->addr)) { + /* exact match */ + DEBUG(" %p is an exact match\n", (void *)tmp); + return tmp; + } + if ((abr == NULL) && (ipv6_addr_is_unspecified(&tmp->addr))) { + abr = tmp; + } + } + if (abr != NULL) { + DEBUG(" using %p\n", (void *)abr); + memcpy(&abr->addr, addr, sizeof(abr->addr)); + } +#if ENABLE_DEBUG + else { + DEBUG(" NIB full\n"); + } +#endif + return abr; +} + +void _nib_abr_remove(const ipv6_addr_t *addr) +{ + assert(addr != NULL); + DEBUG("nib: Removing border router %s\n", ipv6_addr_to_str(addr_str, addr, + sizeof(addr_str))); + for (_nib_abr_entry_t *abr = _abrs; _in_abrs(abr); abr++) { + if (ipv6_addr_equal(addr, &abr->addr)) { + for (int i = 0; i < GNRC_IPV6_NIB_OFFL_NUMOF; i++) { + if (bf_isset(abr->pfxs, i)) { + _nib_pl_remove(&_dsts[i]); + } + } +#if MODULE_GNRC_SIXLOWPAN_CTX + for (int i = 0; i < GNRC_SIXLOWPAN_CTX_SIZE; i++) { + if (bf_isset(abr->ctxs, i)) { + gnrc_sixlowpan_ctx_remove(i); + } + } +#endif + memset(abr, 0, sizeof(_nib_abr_entry_t)); + } + } +} + +void _nib_abr_add_pfx(_nib_abr_entry_t *abr, const _nib_offl_entry_t *offl) +{ + assert((abr != NULL) && (offl != NULL) && (offl->mode & _PL)); + unsigned idx = (unsigned)(_dsts - offl); + + DEBUG("nib: Prefix %s/%u ", + ipv6_addr_to_str(addr_str, &offl->pfx, sizeof(addr_str)), + offl->pfx_len); + DEBUG("came from border router %s\n", ipv6_addr_to_str(addr_str, &abr->addr, + sizeof(addr_str))); + if (idx < GNRC_IPV6_NIB_OFFL_NUMOF) { + bf_set(abr->pfxs, idx); + } +} + +_nib_offl_entry_t *_nib_abr_iter_pfx(const _nib_abr_entry_t *abr, + const _nib_offl_entry_t *last) +{ + if ((last == NULL) || + (((unsigned)(_dsts - last)) < GNRC_IPV6_NIB_OFFL_NUMOF)) { + /* we don't change `ptr`, so dropping const qualifier for now is okay */ + _nib_offl_entry_t *ptr = (_nib_offl_entry_t *)last; + + while ((ptr = _nib_offl_iter(ptr))) { + /* bf_isset() discards const, but doesn't change the array, so + * discarding it on purpose */ + if ((ptr->mode & _PL) && (bf_isset((uint8_t *)abr->pfxs, ptr - _dsts))) { + return ptr; + } + } + } + return NULL; +} + +_nib_abr_entry_t *_nib_abr_iter(const _nib_abr_entry_t *last) +{ + for (const _nib_abr_entry_t *abr = (last) ? (last + 1) : _abrs; + _in_abrs(abr); abr++) { + if (!ipv6_addr_is_unspecified(&abr->addr)) { + /* const modifier provided to assure internal consistency. + * Can now be discarded. */ + return (_nib_abr_entry_t *)abr; + } + } + return NULL; +} +#endif /* GNRC_IPV6_NIB_CONF_MULTIHOP_P6C */ + _nib_offl_entry_t *_nib_pl_add(unsigned iface, const ipv6_addr_t *pfx, unsigned pfx_len, diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h index 0b96040b14..3dd34e6b2f 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.h @@ -23,6 +23,7 @@ #include #include +#include "bitfield.h" #include "evtimer_msg.h" #include "kernel_types.h" #include "mutex.h" @@ -34,6 +35,7 @@ #include "net/gnrc/ipv6/nib/nc.h" #include "net/gnrc/ipv6/nib/conf.h" #include "net/gnrc/pktqueue.h" +#include "net/gnrc/sixlowpan/ctx.h" #include "net/ndp.h" #include "random.h" @@ -221,6 +223,27 @@ typedef struct { uint8_t na_sent; } _nib_iface_t; +/** + * @brief Internal NIB-representation of the authoritative border router + * for multihop prefix and 6LoWPAN context dissemination + */ +typedef struct { + ipv6_addr_t addr; /**< The address of the border router */ + uint32_t version; /**< last received version of the info of + * the _nib_abr_entry_t::addr */ + evtimer_msg_event_t timeout; /**< timeout of the information */ + /** + * @brief Bitfield marking the prefixes in the NIB's off-link entries + * disseminated by _nib_abr_entry_t::addr + */ + BITFIELD(pfxs, GNRC_IPV6_NIB_OFFL_NUMOF); + /** + * @brief Bitfield marking the contexts disseminated by + * _nib_abr_entry_t::addr + */ + BITFIELD(ctxs, GNRC_SIXLOWPAN_CTX_SIZE); +} _nib_abr_entry_t; + /** * @brief Mutex for locking the NIB */ @@ -598,11 +621,7 @@ _nib_offl_entry_t *_nib_pl_add(unsigned iface, * * Corresponding on-link entry is removed, too. */ -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); -} +void _nib_pl_remove(_nib_offl_entry_t *nib_offl); #if GNRC_IPV6_NIB_CONF_ROUTER || DOXYGEN /** @@ -648,6 +667,65 @@ static inline void _nib_ft_remove(_nib_offl_entry_t *nib_offl) } #endif /* GNRC_IPV6_NIB_CONF_ROUTER */ +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C || defined(DOXYGEN) +/** + * @brief Creates or gets an existing authoritative border router. + * + * @pre `addr != NULL` + * + * @param[in] addr Address of the authoritative border router. + * + * @return An authoritative border router entry, on success. + * @return NULL, if no space is left. + */ +_nib_abr_entry_t *_nib_abr_add(const ipv6_addr_t *addr); + +/** + * @brief Removes an authoritative border router + * + * @pre `addr != NULL` + * + * @param[in] addr Address of the authoritative border router. + */ +void _nib_abr_remove(const ipv6_addr_t *addr); + +/** + * @brief Adds a prefix to the managed prefix of the authoritative border + * router + * + * @pre `(abr != NULL) && (offl != NULL) && (offl->mode & _PL)` + * + * @param[in] abr The border router. + * @param[in] offl The prefix to add. + */ +void _nib_abr_add_pfx(_nib_abr_entry_t *abr, const _nib_offl_entry_t *offl); + +/** + * @brief Iterates over an authoritative border router's prefixes + * + * @pre `(abr != NULL)` + * + * @param[in] abr The border router + * @param[in] last Last prefix (NULL to start) + * + * @return entry after @p last. + * @return NULL, if @p last is the last prefix of @p abr or if @p last + * wasn't in NIB (and != NULL). + */ +_nib_offl_entry_t *_nib_abr_iter_pfx(const _nib_abr_entry_t *abr, + const _nib_offl_entry_t *last); + +/** + * @brief Iterates over authoritative border router entries + * + * @param[in] last Last entry (NULL to start). + * + * @return entry after @p last. + * @return NULL, if @p last is the last ABR in the NIB. + */ +_nib_abr_entry_t *_nib_abr_iter(const _nib_abr_entry_t *last); +#endif + /** * @brief Gets (or creates if it not exists) interface information for * neighbor discovery diff --git a/sys/net/gnrc/network_layer/ipv6/nib/nib_abr.c b/sys/net/gnrc/network_layer/ipv6/nib/nib_abr.c new file mode 100644 index 0000000000..5c926b7abe --- /dev/null +++ b/sys/net/gnrc/network_layer/ipv6/nib/nib_abr.c @@ -0,0 +1,57 @@ +/* + * 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 + */ + +#include "net/gnrc/ipv6/nib/abr.h" + +#include "_nib-internal.h" + +#if GNRC_IPV6_NIB_CONF_6LBR && GNRC_IPV6_NIB_CONF_MULTIHOP_P6C +int gnrc_ipv6_nib_abr_add(const ipv6_addr_t *addr) +{ + _nib_abr_entry_t *abr; + _nib_offl_entry_t *offl = NULL; + + mutex_lock(&_nib_mutex); + if ((abr = _nib_abr_add(addr)) == NULL) { + mutex_unlock(&_nib_mutex); + return -ENOMEM; + } + while ((offl = _nib_offl_iter(offl))) { + if (offl->mode & _PL) { + _nib_abr_add_pfx(abr, offl); + } + } +#ifdef MODULE_GNRC_SIXLOWPAN_CTX /* included optionally for NIB testing */ + for (uint8_t id = 0; id < GNRC_SIXLOWPAN_CTX_SIZE; id++) { + if (gnrc_sixlowpan_ctx_lookup_id(id) != NULL) { + bf_set(abr->ctxs, id); + } + } +#endif + mutex_unlock(&_nib_mutex); + return 0; +} + +void gnrc_ipv6_nib_abr_del(const ipv6_addr_t *addr) +{ + mutex_lock(&_nib_mutex); + _nib_abr_remove(addr); + mutex_unlock(&_nib_mutex); +} +#else +typedef int dont_be_pedantic; +#endif + +/** @} */ From 361dc1423fab2db075c1cd6856ab582de26690ba Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Thu, 29 Jun 2017 12:18:21 +0200 Subject: [PATCH 2/2] tests: extend gnrc_ipv6_nib unittests for internal ABR component --- .../tests-gnrc_ipv6_nib/Makefile.include | 4 + .../tests-gnrc_ipv6_nib-abr.c | 102 +++++++++ .../tests-gnrc_ipv6_nib-internal.c | 209 ++++++++++++++++++ .../tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.c | 1 + .../tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.h | 7 + 5 files changed, 323 insertions(+) create mode 100644 tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-abr.c diff --git a/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include b/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include index 69ef7e06ee..12e352ae23 100644 --- a/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include +++ b/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include @@ -5,5 +5,9 @@ CFLAGS += -DGNRC_IPV6_NIB_CONF_ROUTER=1 CFLAGS += -DGNRC_IPV6_NIB_NUMOF=16 CFLAGS += -DGNRC_IPV6_NIB_OFFL_NUMOF=25 CFLAGS += -DGNRC_IPV6_NIB_DEFAULT_ROUTER_NUMOF=4 +CFLAGS += -DGNRC_IPV6_NIB_ABR_NUMOF=4 +CFLAGS += -DGNRC_IPV6_NIB_CONF_6LBR=1 +CFLAGS += -DGNRC_IPV6_NIB_CONF_MULTIHOP_P6C=1 +CFLAGS += -DGNRC_IPV6_NIB_CONF_DC=1 INCLUDES += -I$(RIOTBASE)/sys/net/gnrc/network_layer/ipv6/nib diff --git a/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-abr.c b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-abr.c new file mode 100644 index 0000000000..73efa29c3f --- /dev/null +++ b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-abr.c @@ -0,0 +1,102 @@ +/* + * 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 + */ + +#include + +#include "net/ipv6/addr.h" +#include "net/gnrc/ipv6/nib.h" +#include "net/gnrc/ipv6/nib/abr.h" + +#include "_nib-internal.h" + +#include "unittests-constants.h" + +#include "tests-gnrc_ipv6_nib.h" + +#define GLOBAL_PREFIX { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0 } + +static void set_up(void) +{ + 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(); +} + +/* + * Creates GNRC_IPV6_NIB_ABR_NUMOF authoritative border router list entries with + * different addresses and then tries to create another one + * Expected result: gnrc_ipv6_nib_abr_add() returns -ENOMEM + */ +static void test_nib_abr_add__ENOMEM(void) +{ + ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + for (unsigned i = 0; i < GNRC_IPV6_NIB_ABR_NUMOF; i++) { + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_abr_add(&addr)); + addr.u16[0].u16++; + } + TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_abr_add(&addr)); +} + +/* + * Creates GNRC_IPV6_NIB_ABR_NUMOF authoritative border router list entries with + * different addresses and then tries to add another equal to the last. + * Expected result: should return 0. + */ +static void test_nib_abr_add__success(void) +{ + ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + for (unsigned i = 0; i < GNRC_IPV6_NIB_ABR_NUMOF; i++) { + addr.u16[0].u16++; + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_abr_add(&addr)); + } + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_abr_add(&addr)); +} + +/* + * Creates an authoritative border router list entry and removes it. + * Expected result: system does not crash ;-) + */ +static void test_nib_abr_del__success(void) +{ + ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_abr_add(&addr)); + gnrc_ipv6_nib_abr_del(&addr); +} + +Test *tests_gnrc_ipv6_nib_abr_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_nib_abr_add__ENOMEM), + new_TestFixture(test_nib_abr_add__success), + new_TestFixture(test_nib_abr_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; +} diff --git a/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-internal.c b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-internal.c index abf93e3e22..eaa328db55 100644 --- a/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-internal.c +++ b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-internal.c @@ -1715,6 +1715,201 @@ static void test_nib_ft_remove(void) TEST_ASSERT_NULL(_nib_offl_iter(NULL)); } +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C +/* + * Creates GNRC_IPV6_NIB_ABR_NUMOF ABR entries with different addresses and + * then tries to add another. + * Expected result: should return NULL + */ +static void test_nib_abr_add__no_space_left(void) +{ + ipv6_addr_t addr = { .u64 = { { .u8 = LINK_LOCAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + for (int i = 0; i < GNRC_IPV6_NIB_ABR_NUMOF; i++) { + TEST_ASSERT_NOT_NULL(_nib_abr_add(&addr)); + addr.u64[1].u64++; + } + TEST_ASSERT_NULL(_nib_abr_add(&addr)); +} + +/* + * Creates GNRC_IPV6_NIB_ABR_NUMOF ABR entries with different addresses and then + * tries to add another that is equal to the last. + * Expected result: should return not NULL (the last) + */ +static void test_nib_abr_add__success_duplicate(void) +{ + _nib_abr_entry_t *abr; + ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + for (int i = 0; i < GNRC_IPV6_NIB_ABR_NUMOF; i++) { + addr.u64[1].u64++; + TEST_ASSERT_NOT_NULL((abr = _nib_abr_add(&addr))); + } + TEST_ASSERT(abr == _nib_abr_add(&addr)); +} + +/* + * Creates an ABR entry. + * Expected result: new entry should contain the given address + */ +static void test_nib_abr_add__success(void) +{ + _nib_abr_entry_t *abr; + static const ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + TEST_ASSERT_NOT_NULL((abr = _nib_abr_add(&addr))); + TEST_ASSERT(ipv6_addr_equal(&addr, &abr->addr)); +} + +/* + * Creates an ABR entry and then removes the entry. + * Expected result: the ABR list should be empty + */ +static void test_nib_abr_remove__success(void) +{ + _nib_abr_entry_t *abr = NULL; + static const ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + TEST_ASSERT_NOT_NULL(_nib_abr_add(&addr)); + _nib_abr_remove(&addr); + TEST_ASSERT_NULL(_nib_abr_iter(abr)); +} + +/* + * Creates an ABR entry and tries to add a prefix, that is not in the NIB. + * Expected result: the ABR's prefix list should be unchanged. + */ +static void test_nib_abr_add_pfx__pfx_not_in_nib(void) +{ + _nib_abr_entry_t *abr; + static const ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + _nib_offl_entry_t offl; + + TEST_ASSERT_NOT_NULL((abr = _nib_abr_add(&addr))); + TEST_ASSERT_NULL(_nib_abr_iter_pfx(abr, NULL)); + _nib_abr_add_pfx(abr, &offl); + TEST_ASSERT_NULL(_nib_abr_iter_pfx(abr, NULL)); +} + +/* + * Creates an ABR entry and a prefix and tries to add that prefix. + * Expected result: the ABR's prefix list should be changed. + */ +static void test_nib_abr_add_pfx__pfx_in_nib(void) +{ + _nib_abr_entry_t *abr; + _nib_offl_entry_t *dst; + static const ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + static const ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX } } }; + + + TEST_ASSERT_NOT_NULL((abr = _nib_abr_add(&addr))); + TEST_ASSERT_NOT_NULL((dst = _nib_pl_add(IFACE, &pfx, GLOBAL_PREFIX_LEN, + UINT32_MAX, UINT32_MAX))); + TEST_ASSERT_NULL(_nib_abr_iter_pfx(abr, NULL)); + _nib_abr_add_pfx(abr, dst); + TEST_ASSERT_NOT_NULL(_nib_abr_iter_pfx(abr, NULL)); +} + +/* + * Iterates over prefixes of ABR with no prefix entries + * Expected result: _nib_abr_pfx_iter returns NULL + */ +static void test_nib_abr_iter_pfx__empty(void) +{ + _nib_abr_entry_t *abr; + static const ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + TEST_ASSERT_NOT_NULL((abr = _nib_abr_add(&addr))); + TEST_ASSERT_NULL(_nib_abr_iter_pfx(abr, NULL)); +} + +/* + * Iterates over empty ABR entries + * Expected result: _nib_abr_iter returns NULL + */ +static void test_nib_abr_iter__empty(void) +{ + TEST_ASSERT_NULL(_nib_abr_iter(NULL)); +} + +/* + * Iterates over ABR entries with one element + * Expected result: _nib_abr_iter returns element with NULL, and with that + * element NULL. + */ +static void test_nib_abr_iter__one_elem(void) +{ + _nib_abr_entry_t *abr, *res; + static const ipv6_addr_t addr = { .u64 = { { .u8 = LINK_LOCAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + TEST_ASSERT_NOT_NULL((abr = _nib_abr_add(&addr))); + TEST_ASSERT_NOT_NULL((res = _nib_abr_iter(NULL))); + TEST_ASSERT(res == abr); + TEST_ASSERT_NULL(_nib_abr_iter(res)); +} + +/* + * Iterates over ABR entries with three element + * Expected result: _nib_abr_iter returns element with NULL, with that element + * another, with that element yet another and with the last NULL. + */ +static void test_nib_abr_iter__three_elem(void) +{ + _nib_abr_entry_t *abr1, *abr2, *abr3, *res; + ipv6_addr_t addr = { .u64 = { { .u8 = LINK_LOCAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + TEST_ASSERT_NOT_NULL((abr1 = _nib_abr_add(&addr))); + addr.u64[1].u64++; + TEST_ASSERT_NOT_NULL((abr2 = _nib_abr_add(&addr))); + addr.u64[1].u64++; + TEST_ASSERT_NOT_NULL((abr3 = _nib_abr_add(&addr))); + TEST_ASSERT_NOT_NULL((res = _nib_abr_iter(NULL))); + TEST_ASSERT(res == abr1); + TEST_ASSERT_NOT_NULL((res = _nib_abr_iter(res))); + TEST_ASSERT(res == abr2); + TEST_ASSERT_NOT_NULL((res = _nib_abr_iter(res))); + TEST_ASSERT(res == abr3); + TEST_ASSERT_NULL(_nib_abr_iter(res)); +} + +/* + * Iterates over ABR entries with two elements, where there is a hole in the + * internal array + * Expected result: _nib_abr_iter returns element with NULL, with that element + * another, and with the last NULL. + */ +static void test_nib_abr_iter__three_elem_middle_removed(void) +{ + _nib_abr_entry_t *abr1, *abr2, *res; + ipv6_addr_t addr = { .u64 = { { .u8 = LINK_LOCAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + + TEST_ASSERT_NOT_NULL((abr1 = _nib_abr_add(&addr))); + addr.u64[1].u64++; + TEST_ASSERT_NOT_NULL(_nib_abr_add(&addr)); + addr.u64[1].u64++; + TEST_ASSERT_NOT_NULL((abr2 = _nib_abr_add(&addr))); + addr.u64[1].u64--; + _nib_abr_remove(&addr); + TEST_ASSERT_NOT_NULL((res = _nib_abr_iter(NULL))); + TEST_ASSERT(res == abr1); + TEST_ASSERT_NOT_NULL((res = _nib_abr_iter(res))); + TEST_ASSERT(res == abr2); + TEST_ASSERT_NULL(_nib_abr_iter(res)); +} +#endif + /* * Creates GNRC_NETIF_NUMOF interfaces and then tries to add another. * Expected result: should return NULL @@ -1826,6 +2021,20 @@ Test *tests_gnrc_ipv6_nib_internal_tests(void) new_TestFixture(test_nib_pl_remove), new_TestFixture(test_nib_ft_add__success), new_TestFixture(test_nib_ft_remove), +#if GNRC_IPV6_NIB_CONF_MULTIHOP_P6C + new_TestFixture(test_nib_abr_add__no_space_left), + new_TestFixture(test_nib_abr_add__success_duplicate), + new_TestFixture(test_nib_abr_add__success), + new_TestFixture(test_nib_abr_remove__success), + new_TestFixture(test_nib_abr_add_pfx__pfx_not_in_nib), + new_TestFixture(test_nib_abr_add_pfx__pfx_in_nib), + new_TestFixture(test_nib_abr_iter_pfx__empty), + /* rest of _nib_abr_iter_pfx() tested through _nib_abr_add_pfx() tests */ + new_TestFixture(test_nib_abr_iter__empty), + new_TestFixture(test_nib_abr_iter__one_elem), + new_TestFixture(test_nib_abr_iter__three_elem), + new_TestFixture(test_nib_abr_iter__three_elem_middle_removed), +#endif new_TestFixture(test_nib_iface_get__no_space_left), new_TestFixture(test_nib_iface_get__success), }; diff --git a/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.c b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.c index 93258f94f9..9ac03846fd 100644 --- a/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.c +++ b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.c @@ -18,6 +18,7 @@ void tests_gnrc_ipv6_nib(void) { TESTS_RUN(tests_gnrc_ipv6_nib_internal_tests()); + TESTS_RUN(tests_gnrc_ipv6_nib_abr_tests()); TESTS_RUN(tests_gnrc_ipv6_nib_nc_tests()); TESTS_RUN(tests_gnrc_ipv6_nib_pl_tests()); } diff --git a/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.h b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.h index a7763061e0..6e210d0b75 100644 --- a/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.h +++ b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.h @@ -36,6 +36,13 @@ void tests_gnrc_ipv6_nib(void); */ Test *tests_gnrc_ipv6_nib_internal_tests(void); +/** + * @brief Generates tests for authoritative border router list view + * + * @return embUnit tests if successful, NULL if not. + */ +Test *tests_gnrc_ipv6_nib_abr_tests(void); + /** * @brief Generates tests for neighbor cache view *