diff --git a/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include b/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include index ccae089522..2370879fe5 100644 --- a/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include +++ b/tests/unittests/tests-gnrc_ipv6_nib/Makefile.include @@ -1,4 +1,5 @@ USEMODULE += gnrc_ipv6_nib +USEMODULE += gnrc_ipv6_netif CFLAGS += -DGNRC_IPV6_NIB_NUMOF=16 CFLAGS += -DGNRC_IPV6_NIB_DEFAULT_ROUTER_NUMOF=4 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 2b9c7ebb7f..5cd7b8e5f3 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 @@ -431,7 +431,7 @@ static void test_nib_nc_add__success_duplicate(void) node->info |= GNRC_IPV6_NIB_NC_INFO_AR_STATE_REGISTERED; } TEST_ASSERT(node == _nib_nc_add(&addr, iface, - GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE)); + GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE)); } /* diff --git a/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-nc.c b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-nc.c new file mode 100644 index 0000000000..f700008389 --- /dev/null +++ b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-nc.c @@ -0,0 +1,346 @@ +/* + * 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 + +#include "net/gnrc/ipv6/nib.h" +#include "net/gnrc/ipv6/nib/nc.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 IFACE (6) + +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_NUMOF neighbor cache entries with different addresses + * and then tries to create another one + * Expected result: gnrc_ipv6_nib_nc_set() returns -ENOMEM + */ +static void test_nib_nc_set__ENOMEM_diff_addr(void) +{ + ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + uint8_t l2addr[] = L2ADDR; + + for (unsigned i = 0; i < GNRC_IPV6_NIB_NUMOF; i++) { + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_nc_set(&addr, IFACE, l2addr, + sizeof(l2addr))); + addr.u64[1].u64++; + l2addr[7]++; + } + TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_nc_set(&addr, IFACE, l2addr, + sizeof(l2addr))); +} + +/* + * Creates GNRC_IPV6_NIB_NUMOF neighbor cache entries with different interfaces + * and then tries to create another one + * Expected result: gnrc_ipv6_nib_nc_set() returns -ENOMEM + */ +static void test_nib_nc_set__ENOMEM_diff_iface(void) +{ + static const ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + static const uint8_t l2addr[] = L2ADDR; + unsigned iface = IFACE; + + for (unsigned i = 0; i < GNRC_IPV6_NIB_NUMOF; i++) { + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_nc_set(&addr, iface, l2addr, + sizeof(l2addr))); + iface++; + } + TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_nc_set(&addr, iface, l2addr, + sizeof(l2addr))); +} + +/* + * Creates GNRC_IPV6_NIB_NUMOF neighbor cache entries with different addresses + * and interfaces and then tries to create another one + * Expected result: gnrc_ipv6_nib_nc_set() returns -ENOMEM + */ +static void test_nib_nc_set__ENOMEM_diff_addr_iface(void) +{ + ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + uint8_t l2addr[] = L2ADDR; + unsigned iface = IFACE; + + for (unsigned i = 0; i < GNRC_IPV6_NIB_NUMOF; i++) { + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_nc_set(&addr, iface, l2addr, + sizeof(l2addr))); + addr.u64[1].u64++; + iface++; + l2addr[7]++; + } + TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_nc_set(&addr, iface, l2addr, + sizeof(l2addr))); +} + +/* + * Creates a neighbor cache entry. + * Expected result: a new entry should exist and contain the given address + * and interface + */ +static void test_nib_nc_set__success(void) +{ + void *iter_state = NULL; + ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + uint8_t l2addr[] = L2ADDR; + gnrc_ipv6_nib_nc_t nce; + + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_nc_set(&addr, IFACE, l2addr, + sizeof(l2addr))); + TEST_ASSERT(gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); + TEST_ASSERT_EQUAL_INT(0, memcmp(&nce.ipv6, &addr, sizeof(addr))); + TEST_ASSERT_EQUAL_INT(0, memcmp(&nce.l2addr, &l2addr, sizeof(l2addr))); + TEST_ASSERT_EQUAL_INT(sizeof(l2addr), nce.l2addr_len); + TEST_ASSERT_EQUAL_INT(IFACE, gnrc_ipv6_nib_nc_get_iface(&nce)); + TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED, + gnrc_ipv6_nib_nc_get_nud_state(&nce)); + TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_AR_STATE_MANUAL, + gnrc_ipv6_nib_nc_get_ar_state(&nce)); + TEST_ASSERT(!gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); +} + +/* + * Creates GNRC_IPV6_NIB_NUMOF neighbor cache entries with different IP + * addresses and interface identifiers and then tries to add another that is + * equal to the last. + * Expected result: gnrc_ipv6_nib_nc_set() returns 0 + */ +static void test_nib_nc_set__success_duplicate(void) +{ + ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + uint8_t l2addr[] = L2ADDR; + unsigned iface = 0; + + for (unsigned i = 0; i < GNRC_IPV6_NIB_NUMOF; i++) { + addr.u64[1].u64++; + iface++; + l2addr[7]++; + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_nc_set(&addr, iface, l2addr, + sizeof(l2addr))); + } + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_nc_set(&addr, iface, l2addr, + sizeof(l2addr))); +} + +/* + * Creates GNRC_IPV6_NIB_NUMOF neighbor cache entries with different addresses + * and interfaces and then tries to delete one with yet another address. + * Expected result: There should be still GNRC_IPV6_NIB_NUMOF entries in the + * neigbor cache + */ +static void test_nib_nc_del__unknown(void) +{ + void *iter_state = NULL; + ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + uint8_t l2addr[] = L2ADDR; + gnrc_ipv6_nib_nc_t nce; + unsigned iface = IFACE, count = 0; + + for (unsigned i = 0; i < GNRC_IPV6_NIB_NUMOF; i++) { + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_nc_set(&addr, iface, l2addr, + sizeof(l2addr))); + addr.u64[1].u64++; + iface++; + l2addr[7]++; + } + gnrc_ipv6_nib_nc_del(&addr); + while (gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)) { + count++; + } + TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NUMOF, count); +} + +/* + * Creates a neighbor cache entry and removes it. + * Expected result: neighbor cache should be empty + */ +static void test_nib_nc_del__success(void) +{ + void *iter_state = NULL; + static const ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + uint8_t l2addr[] = L2ADDR; + gnrc_ipv6_nib_nc_t nce; + + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_nc_set(&addr, IFACE, l2addr, + sizeof(l2addr))); + gnrc_ipv6_nib_nc_del(&addr); + TEST_ASSERT(!gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); +} + +/* + * Creates a non-manual neighbor cache entry (as the NIB would create it on an + * incoming NDP packet), sets it to UNREACHABLE and then calls + * gnrc_ipv6_nib_mark_reachable(). + * Expected result: The created entry should be the only entry and its state + * should be still unreachable. The event timer is still empty. + */ +static void test_nib_nc_mark_reachable__not_in_neighbor_cache(void) +{ + void *iter_state = NULL; + ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + gnrc_ipv6_nib_nc_t nce; + + TEST_ASSERT_NOT_NULL(_nib_nc_add(&addr, IFACE, + GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE)); + + /* check pre-state */ + TEST_ASSERT(gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); + TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE, + gnrc_ipv6_nib_nc_get_nud_state(&nce)); + TEST_ASSERT(!gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); + TEST_ASSERT_NULL(_nib_evtimer.events); + + addr.u64[1].u64++; + gnrc_ipv6_nib_nc_mark_reachable(&addr); + /* check if entry is still unmanaged */ + TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE, + gnrc_ipv6_nib_nc_get_nud_state(&nce)); + /* check if there are still no events */ + TEST_ASSERT_NULL(_nib_evtimer.events); + /* check if still the only entry */ + iter_state = NULL; + TEST_ASSERT(gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); + TEST_ASSERT(!gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); +} + +/* + * Creates a manual neighbor cache entry , sets it to UNREACHABLE and then calls + * gnrc_ipv6_nib_mark_reachable(). + * Expected result: The created entry should be the only entry and its state + * should be still unreachable. The event timer is still empty. + */ +static void test_nib_nc_mark_reachable__unmanaged(void) +{ + void *iter_state = NULL; + static const ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + gnrc_ipv6_nib_nc_t nce; + + TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_nc_set(&addr, IFACE, NULL, 0)); + /* check pre-state */ + TEST_ASSERT(gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); + TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED, + gnrc_ipv6_nib_nc_get_nud_state(&nce)); + TEST_ASSERT(!gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); + TEST_ASSERT_NULL(_nib_evtimer.events); + gnrc_ipv6_nib_nc_mark_reachable(&addr); + /* check if entry is still unmanaged */ + TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNMANAGED, + gnrc_ipv6_nib_nc_get_nud_state(&nce)); + /* check if there are still no events */ + TEST_ASSERT_NULL(_nib_evtimer.events); + /* check if still the only entry */ + iter_state = NULL; + TEST_ASSERT(gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); + TEST_ASSERT(!gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); +} + +/* + * Creates a non-manual neighbor cache entry (as the NIB would create it on an + * incoming NDP packet), sets it to a state unequal to REACHABLE and then calls + * gnrc_ipv6_nib_mark_reachable() + * Expected result: the neighbor cache entry should be in state REACHABLE and a + * reachability timeout event for that entry is in the event timer. + */ +static void test_nib_nc_mark_reachable__success(void) +{ + void *iter_state = NULL; + _nib_onl_entry_t *node; +#if GNRC_IPV6_NIB_CONF_ARSM + evtimer_msg_event_t *event; +#endif + _nib_iface_t *iface; + static const ipv6_addr_t addr = { .u64 = { { .u8 = GLOBAL_PREFIX }, + { .u64 = TEST_UINT64 } } }; + gnrc_ipv6_nib_nc_t nce; + + TEST_ASSERT_NOT_NULL((node = _nib_nc_add(&addr, IFACE, + GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE))); + /* set an "infinite" reachability time */ + iface = _nib_iface_get(_nib_onl_get_if(node)); + iface->reach_time = UINT32_MAX; + + /* check pre-state */ + TEST_ASSERT(gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); + TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_NUD_STATE_UNREACHABLE, + gnrc_ipv6_nib_nc_get_nud_state(&nce)); + TEST_ASSERT(!gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); + TEST_ASSERT_NULL(_nib_evtimer.events); + + gnrc_ipv6_nib_nc_mark_reachable(&addr); + + iter_state = NULL; + TEST_ASSERT(gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); +#if GNRC_IPV6_NIB_CONF_ARSM + /* check if entry is reachable */ + TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_NC_INFO_NUD_STATE_REACHABLE, + gnrc_ipv6_nib_nc_get_nud_state(&nce)); + /* check if there now is an event for reachability timeout of node */ + TEST_ASSERT_NOT_NULL((event = (evtimer_msg_event_t *)_nib_evtimer.events)); + TEST_ASSERT_EQUAL_INT(GNRC_IPV6_NIB_REACH_TIMEOUT, event->msg.type); + TEST_ASSERT_MESSAGE(node == event->msg.content.ptr, + "event's context is not node"); +#endif + /* check if still the only entry */ + TEST_ASSERT(!gnrc_ipv6_nib_nc_iter(0, &iter_state, &nce)); +} + +Test *tests_gnrc_ipv6_nib_nc_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_nib_nc_set__ENOMEM_diff_addr), + new_TestFixture(test_nib_nc_set__ENOMEM_diff_iface), + new_TestFixture(test_nib_nc_set__ENOMEM_diff_addr_iface), + new_TestFixture(test_nib_nc_set__success), + new_TestFixture(test_nib_nc_set__success_duplicate), + new_TestFixture(test_nib_nc_del__unknown), + new_TestFixture(test_nib_nc_del__success), + new_TestFixture(test_nib_nc_mark_reachable__not_in_neighbor_cache), + new_TestFixture(test_nib_nc_mark_reachable__unmanaged), + new_TestFixture(test_nib_nc_mark_reachable__success), + /* gnrc_ipv6_nib_nc_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.c b/tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib.c index c1c4f83815..7682229e50 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,4 +18,5 @@ void tests_gnrc_ipv6_nib(void) { TESTS_RUN(tests_gnrc_ipv6_nib_internal_tests()); + TESTS_RUN(tests_gnrc_ipv6_nib_nc_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 1e3952b6a0..cc58551781 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 neighbor cache view + * + * @return embUnit tests if successful, NULL if not. + */ +Test *tests_gnrc_ipv6_nib_nc_tests(void); + #ifdef __cplusplus } #endif