mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #20329 from fabian18/nib_rtr_fixes
nib: some fixes when a router or a prefix is deleted
This commit is contained in:
commit
d6d9d5f3da
@ -25,6 +25,7 @@
|
||||
#include "net/gnrc/ipv6/nib/nc.h"
|
||||
#include "net/gnrc/ipv6/nib.h"
|
||||
#include "net/gnrc/netif/internal.h"
|
||||
#include "net/ipv6/addr.h"
|
||||
#include "random.h"
|
||||
|
||||
#include "_nib-internal.h"
|
||||
@ -378,6 +379,20 @@ void _nib_drl_remove(_nib_dr_entry_t *nib_dr)
|
||||
if (nib_dr->next_hop != NULL) {
|
||||
_evtimer_del(&nib_dr->rtr_timeout);
|
||||
nib_dr->next_hop->mode &= ~(_DRL);
|
||||
#if IS_ACTIVE(CONFIG_GNRC_IPV6_NIB_DC)
|
||||
/* When removing a router from the Default
|
||||
Router list, the node MUST update the Destination Cache in such a way
|
||||
that all entries using the router perform next-hop determination
|
||||
again rather than continue sending traffic to the (deleted) router.
|
||||
(https://datatracker.ietf.org/doc/html/rfc4861#section-6.3.5)
|
||||
*/
|
||||
_nib_offl_entry_t *dc = NULL;
|
||||
while ((dc = _nib_offl_iter(dc))) {
|
||||
if ((dc->mode & _DC) && dc->next_hop == nib_dr->next_hop) {
|
||||
_nib_dc_remove(dc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
_nib_onl_clear(nib_dr->next_hop);
|
||||
memset(nib_dr, 0, sizeof(_nib_dr_entry_t));
|
||||
}
|
||||
@ -538,21 +553,28 @@ static inline bool _in_abrs(const _nib_abr_entry_t *abr)
|
||||
|
||||
void _nib_offl_clear(_nib_offl_entry_t *dst)
|
||||
{
|
||||
if (dst->next_hop != NULL) {
|
||||
_nib_offl_entry_t *ptr;
|
||||
for (ptr = _dsts; _in_dsts(ptr); ptr++) {
|
||||
/* there is another dst pointing to next-hop => only remove dst */
|
||||
if ((dst != ptr) && (dst->next_hop == ptr->next_hop)) {
|
||||
break;
|
||||
if (dst->mode == _EMPTY) {
|
||||
if (dst->next_hop != NULL) {
|
||||
_nib_offl_entry_t *ptr;
|
||||
for (ptr = _dsts; _in_dsts(ptr); ptr++) {
|
||||
/* there is another dst pointing to next-hop => only remove dst */
|
||||
if ((dst != ptr) && (dst->next_hop == ptr->next_hop)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* we iterated and found no further dst pointing to next-hop */
|
||||
if (!_in_dsts(ptr)) {
|
||||
dst->next_hop->mode &= ~(_DST);
|
||||
_nib_onl_clear(dst->next_hop);
|
||||
}
|
||||
}
|
||||
/* we iterated and found no further dst pointing to next-hop */
|
||||
if (!_in_dsts(ptr)) {
|
||||
dst->next_hop->mode &= ~(_DST);
|
||||
_nib_onl_clear(dst->next_hop);
|
||||
}
|
||||
memset(dst, 0, sizeof(_nib_offl_entry_t));
|
||||
}
|
||||
else {
|
||||
DEBUG("nib: offlink entry %s/%u with mode %u not cleared\n",
|
||||
ipv6_addr_to_str(addr_str, &dst->pfx, sizeof(addr_str)),
|
||||
dst->pfx_len, dst->mode);
|
||||
}
|
||||
}
|
||||
|
||||
_nib_offl_entry_t *_nib_offl_iter(const _nib_offl_entry_t *last)
|
||||
|
@ -1458,17 +1458,18 @@ static void _handle_rtr_timeout(_nib_dr_entry_t *router)
|
||||
{
|
||||
if ((router->next_hop != NULL) && (router->next_hop->mode & _DRL)) {
|
||||
_nib_offl_entry_t *route = NULL;
|
||||
unsigned iface = _nib_onl_get_if(router->next_hop);
|
||||
ipv6_addr_t addr = router->next_hop->ipv6;
|
||||
_nib_onl_entry_t *next_hop = router->next_hop;
|
||||
|
||||
_nib_drl_remove(router);
|
||||
/* also remove all routes to that router */
|
||||
/* The Router Lifetime applies only to
|
||||
the router's usefulness as a default router; it
|
||||
does not apply to information contained in other
|
||||
message fields or options. Options that need time
|
||||
limits for their information include their own
|
||||
lifetime fields.
|
||||
(https://datatracker.ietf.org/doc/html/rfc4861#section-4.2) */
|
||||
while ((route = _nib_offl_iter(route))) {
|
||||
if ((route->next_hop != NULL) &&
|
||||
(_nib_onl_get_if(route->next_hop) == iface) &&
|
||||
(ipv6_addr_equal(&route->next_hop->ipv6, &addr))) {
|
||||
route->mode = _EMPTY;
|
||||
route->next_hop->mode &= ~_DST;
|
||||
if (route->next_hop == next_hop) {
|
||||
_nib_offl_clear(route);
|
||||
/* XXX routing protocol gets informed in case NUD
|
||||
* determines ipv6->src (still in neighbor cache) to be
|
||||
|
@ -817,11 +817,11 @@ static void test_handle_pkt__rtr_sol(void)
|
||||
static size_t _set_rtr_adv(const ipv6_addr_t *ipv6_src,
|
||||
uint8_t ipv6_hl, uint8_t rtr_adv_code,
|
||||
bool set_rtr_adv_fields,
|
||||
uint8_t rtr_adv_flags,
|
||||
uint8_t rtr_adv_flags, uint32_t t_rtr_reachable_ms, uint16_t t_rtr_alive_s,
|
||||
const uint8_t *sl2ao_addr, size_t sl2ao_addr_len,
|
||||
uint16_t mtu,
|
||||
const ipv6_addr_t *pfx, unsigned pfx_len,
|
||||
uint8_t pfx_flags)
|
||||
uint8_t pfx_flags, uint32_t t_pfx_valid_s, uint32_t t_pfx_pref_s)
|
||||
{
|
||||
size_t icmpv6_len = sizeof(ndp_rtr_adv_t);
|
||||
ndp_rtr_adv_t *rtr_adv = (ndp_rtr_adv_t *)icmpv6;
|
||||
@ -835,8 +835,8 @@ static size_t _set_rtr_adv(const ipv6_addr_t *ipv6_src,
|
||||
rtr_adv->flags = rtr_adv_flags;
|
||||
if (set_rtr_adv_fields) {
|
||||
rtr_adv->cur_hl = _CUR_HL,
|
||||
rtr_adv->ltime = byteorder_htons(_RTR_LTIME);
|
||||
rtr_adv->reach_time = byteorder_htonl(_REACH_TIME);
|
||||
rtr_adv->ltime = byteorder_htons(t_rtr_alive_s);
|
||||
rtr_adv->reach_time = byteorder_htonl(t_rtr_reachable_ms);
|
||||
rtr_adv->retrans_timer = byteorder_htonl(_RETRANS_TIMER);
|
||||
}
|
||||
|
||||
@ -857,8 +857,8 @@ static size_t _set_rtr_adv(const ipv6_addr_t *ipv6_src,
|
||||
pio->len = NDP_OPT_PI_LEN;
|
||||
pio->prefix_len = pfx_len;
|
||||
pio->flags = pfx_flags;
|
||||
pio->valid_ltime = byteorder_htonl(_PIO_PFX_LTIME);
|
||||
pio->pref_ltime = byteorder_htonl(_PIO_PFX_LTIME);
|
||||
pio->valid_ltime = byteorder_htonl(t_pfx_valid_s);
|
||||
pio->pref_ltime = byteorder_htonl(t_pfx_pref_s);
|
||||
ipv6_addr_init_prefix(&pio->prefix, pfx, pfx_len);
|
||||
icmpv6_len += sizeof(ndp_opt_pi_t);
|
||||
}
|
||||
@ -923,9 +923,11 @@ static void test_handle_pkt__rtr_adv__invalid_src(void)
|
||||
void *state = NULL;
|
||||
size_t icmpv6_len = _set_rtr_adv(&_rem_gb,
|
||||
NDP_HOP_LIMIT, 0U, true, 0U,
|
||||
_REACH_TIME, _RTR_LTIME,
|
||||
_loc_l2, sizeof(_loc_l2),
|
||||
32397U, &_loc_gb, _LOC_GB_PFX_LEN,
|
||||
NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
|
||||
NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
|
||||
_PIO_PFX_LTIME, _PIO_PFX_LTIME);
|
||||
_netif_exp_t exp_netif;
|
||||
|
||||
_get_netif_exp(_mock_netif, &exp_netif);
|
||||
@ -946,9 +948,11 @@ static void test_handle_pkt__rtr_adv__invalid_hl(void)
|
||||
void *state = NULL;
|
||||
size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
|
||||
194U, 0U, true, 0U,
|
||||
_REACH_TIME, _RTR_LTIME,
|
||||
_loc_l2, sizeof(_loc_l2),
|
||||
32397U, &_loc_gb, _LOC_GB_PFX_LEN,
|
||||
NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
|
||||
NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
|
||||
_PIO_PFX_LTIME, _PIO_PFX_LTIME);
|
||||
_netif_exp_t exp_netif;
|
||||
|
||||
_get_netif_exp(_mock_netif, &exp_netif);
|
||||
@ -969,9 +973,11 @@ static void test_handle_pkt__rtr_adv__invalid_code(void)
|
||||
void *state = NULL;
|
||||
size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
|
||||
NDP_HOP_LIMIT, 201U, true, 0U,
|
||||
_REACH_TIME, _RTR_LTIME,
|
||||
_loc_l2, sizeof(_loc_l2),
|
||||
32397U, &_loc_gb, _LOC_GB_PFX_LEN,
|
||||
NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
|
||||
NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
|
||||
_PIO_PFX_LTIME, _PIO_PFX_LTIME);
|
||||
_netif_exp_t exp_netif;
|
||||
|
||||
_get_netif_exp(_mock_netif, &exp_netif);
|
||||
@ -994,9 +1000,11 @@ static void test_handle_pkt__rtr_adv__invalid_icmpv6_len(void)
|
||||
|
||||
_get_netif_exp(_mock_netif, &exp_netif);
|
||||
_set_rtr_adv(&_rem_ll, NDP_HOP_LIMIT, 201U, true, 0U,
|
||||
_REACH_TIME, _RTR_LTIME,
|
||||
_loc_l2, sizeof(_loc_l2),
|
||||
32397U, &_loc_gb, _LOC_GB_PFX_LEN,
|
||||
NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
|
||||
NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
|
||||
_PIO_PFX_LTIME, _PIO_PFX_LTIME);
|
||||
gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6,
|
||||
sizeof(ndp_rtr_adv_t) - 1);
|
||||
TEST_ASSERT_MESSAGE(!gnrc_ipv6_nib_nc_iter(0, &state, &nce),
|
||||
@ -1015,9 +1023,11 @@ static void test_handle_pkt__rtr_adv__invalid_opt_len(void)
|
||||
void *state = NULL;
|
||||
size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
|
||||
NDP_HOP_LIMIT, 201U, true, 0U,
|
||||
_REACH_TIME, _RTR_LTIME,
|
||||
_loc_l2, sizeof(_loc_l2),
|
||||
32397U, &_loc_gb, _LOC_GB_PFX_LEN,
|
||||
NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A);
|
||||
NDP_OPT_PI_FLAGS_L | NDP_OPT_PI_FLAGS_A,
|
||||
_PIO_PFX_LTIME, _PIO_PFX_LTIME);
|
||||
ndp_opt_t *opt = (ndp_opt_t *)&_buffer[icmpv6_len];
|
||||
_netif_exp_t exp_netif;
|
||||
|
||||
@ -1047,10 +1057,11 @@ static void test_handle_pkt__rtr_adv__success(uint8_t rtr_adv_flags,
|
||||
void *state = NULL;
|
||||
size_t icmpv6_len = _set_rtr_adv(&_rem_ll, NDP_HOP_LIMIT, 0U,
|
||||
set_rtr_adv_fields, rtr_adv_flags,
|
||||
_REACH_TIME, _RTR_LTIME,
|
||||
(sl2ao) ? _rem_l2 : NULL, sizeof(_rem_l2),
|
||||
(mtuo) ? 32397U : 0U,
|
||||
(pio) ? &_loc_gb : NULL, _LOC_GB_PFX_LEN,
|
||||
pio_flags);
|
||||
pio_flags, _PIO_PFX_LTIME, _PIO_PFX_LTIME);
|
||||
const unsigned exp_addr_count = _netif_addr_count(_mock_netif);
|
||||
_netif_exp_t exp_netif;
|
||||
|
||||
@ -1279,6 +1290,108 @@ static void test_change_rtr_adv_iface(void)
|
||||
TEST_ASSERT_EQUAL_INT(0, msg_avail());
|
||||
}
|
||||
|
||||
static void test_handle_router_timeout(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t route;
|
||||
gnrc_ipv6_nib_pl_t prefix;
|
||||
void *state = NULL;
|
||||
uint32_t t_rtr_alive_s = 5; /* [0, 9000]s, 0: not a default router */
|
||||
size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
|
||||
NDP_HOP_LIMIT, 0U, true, 0U,
|
||||
_REACH_TIME, t_rtr_alive_s,
|
||||
_rem_l2, sizeof(_rem_l2),
|
||||
32397U, &_loc_gb, _LOC_GB_PFX_LEN,
|
||||
NDP_OPT_PI_FLAGS_L,
|
||||
_PIO_PFX_LTIME, _PIO_PFX_LTIME);
|
||||
gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
|
||||
/* check that prefix has been added */
|
||||
bool pfx = false, rtr = false;
|
||||
while (gnrc_ipv6_nib_pl_iter(_mock_netif->pid, &state, &prefix)) {
|
||||
pfx = true;
|
||||
TEST_ASSERT_MESSAGE(ipv6_addr_match_prefix(&prefix.pfx, &_loc_gb) >= _LOC_GB_PFX_LEN,
|
||||
"Prefix is not the one from the RA");
|
||||
}
|
||||
if (!pfx) {
|
||||
TEST_ASSERT_MESSAGE(false, "Prefix not added");
|
||||
}
|
||||
/* check that router has been added */
|
||||
state = NULL;
|
||||
while (gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route)) {
|
||||
if (ipv6_addr_is_unspecified(&route.dst)) {
|
||||
rtr = true;
|
||||
TEST_ASSERT_MESSAGE(ipv6_addr_equal(&_rem_ll, &route.next_hop),
|
||||
"Default route is not via RA source");
|
||||
}
|
||||
}
|
||||
if (!rtr) {
|
||||
TEST_ASSERT_MESSAGE(false, "Default route not added");
|
||||
}
|
||||
/* timeout router by RA with lifetime 0 */
|
||||
icmpv6_len = _set_rtr_adv(&_rem_ll,
|
||||
NDP_HOP_LIMIT, 0U, true, 0U,
|
||||
_REACH_TIME, 0,
|
||||
_rem_l2, sizeof(_rem_l2),
|
||||
32397U, &_loc_gb, _LOC_GB_PFX_LEN,
|
||||
NDP_OPT_PI_FLAGS_L,
|
||||
_PIO_PFX_LTIME, _PIO_PFX_LTIME);
|
||||
gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
|
||||
/* check that default router has been timed out */
|
||||
state = NULL;
|
||||
while (gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route)) {
|
||||
if (ipv6_addr_is_unspecified(&route.dst)) {
|
||||
TEST_ASSERT_MESSAGE(ipv6_addr_equal(&_rem_ll, &route.next_hop),
|
||||
"Default route was not deleted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_handle_prefix_timeout(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t route;
|
||||
gnrc_ipv6_nib_pl_t prefix;
|
||||
void *state = NULL;
|
||||
uint32_t t_rtr_alive_s = 0; /* [0, 9000]s, 0: not a default router */
|
||||
size_t icmpv6_len = _set_rtr_adv(&_rem_ll,
|
||||
NDP_HOP_LIMIT, 0U, true, 0U,
|
||||
_REACH_TIME, t_rtr_alive_s,
|
||||
_rem_l2, sizeof(_rem_l2),
|
||||
32397U, &_loc_gb, _LOC_GB_PFX_LEN,
|
||||
NDP_OPT_PI_FLAGS_L,
|
||||
_PIO_PFX_LTIME, _PIO_PFX_LTIME);
|
||||
gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
|
||||
/* check that prefix has been added */
|
||||
bool pfx = false;
|
||||
while (gnrc_ipv6_nib_pl_iter(_mock_netif->pid, &state, &prefix)) {
|
||||
pfx = true;
|
||||
TEST_ASSERT_MESSAGE(ipv6_addr_match_prefix(&prefix.pfx, &_loc_gb) >= _LOC_GB_PFX_LEN,
|
||||
"Prefix is not the one from the RA");
|
||||
}
|
||||
if (!pfx) {
|
||||
TEST_ASSERT_MESSAGE(false, "Prefix not added");
|
||||
}
|
||||
/* check that router has not been added as default router */
|
||||
state = NULL;
|
||||
while (gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &route)) {
|
||||
if (ipv6_addr_is_unspecified(&route.dst)) {
|
||||
TEST_ASSERT_MESSAGE(false, "Router should not have been added as a default router");
|
||||
}
|
||||
}
|
||||
/* timeout router by RA with lifetime 0 */
|
||||
icmpv6_len = _set_rtr_adv(&_rem_ll,
|
||||
NDP_HOP_LIMIT, 0U, true, 0U,
|
||||
_REACH_TIME, 0,
|
||||
_rem_l2, sizeof(_rem_l2),
|
||||
32397U, &_loc_gb, _LOC_GB_PFX_LEN,
|
||||
NDP_OPT_PI_FLAGS_L,
|
||||
0, 0);
|
||||
gnrc_ipv6_nib_handle_pkt(_mock_netif, ipv6, icmpv6, icmpv6_len);
|
||||
/* check that prefix has been timed out */
|
||||
state = NULL;
|
||||
if (gnrc_ipv6_nib_pl_iter(_mock_netif->pid, &state, &prefix)) {
|
||||
TEST_ASSERT_MESSAGE(false, "Prefix has been timed out but is still in use");
|
||||
}
|
||||
}
|
||||
|
||||
static Test *tests_gnrc_ipv6_nib(void)
|
||||
{
|
||||
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||
@ -1341,6 +1454,8 @@ static Test *tests_gnrc_ipv6_nib(void)
|
||||
* we do not have access to the (internally defined) contexts required
|
||||
* for it */
|
||||
new_TestFixture(test_change_rtr_adv_iface),
|
||||
new_TestFixture(test_handle_router_timeout),
|
||||
new_TestFixture(test_handle_prefix_timeout),
|
||||
};
|
||||
|
||||
EMB_UNIT_TESTCALLER(tests, _set_up, NULL, fixtures);
|
||||
|
Loading…
Reference in New Issue
Block a user