Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gnrc_ipv6_nib: Force unspecified next hop addresses #20371

Merged
merged 4 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 28 additions & 19 deletions sys/net/gnrc/network_layer/ipv6/nib/_nib-internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,11 @@ void _nib_release(void)
static inline bool _addr_equals(const ipv6_addr_t *addr,
const _nib_onl_entry_t *node)
{
return (addr == NULL) || ipv6_addr_is_unspecified(&node->ipv6) ||
(ipv6_addr_equal(addr, &node->ipv6));
if (addr == NULL) {
return ipv6_addr_is_unspecified(&node->ipv6);
} else {
return ipv6_addr_equal(addr, &node->ipv6);
}
}

_nib_onl_entry_t *_nib_onl_alloc(const ipv6_addr_t *addr, unsigned iface)
Expand Down Expand Up @@ -501,28 +504,34 @@ _nib_offl_entry_t *_nib_offl_alloc(const ipv6_addr_t *next_hop, unsigned iface,
_nib_offl_entry_t *tmp = &_dsts[i];
_nib_onl_entry_t *tmp_node = tmp->next_hop;

if ((tmp->pfx_len == pfx_len) && /* prefix length matches and */
(tmp_node != NULL) && /* there is a next hop that */
(_nib_onl_get_if(tmp_node) == iface) && /* has a matching interface and */
_addr_equals(next_hop, tmp_node) && /* equal address to next_hop, also */
(ipv6_addr_match_prefix(&tmp->pfx, pfx) >= pfx_len)) { /* the prefix matches */
/* exact match (or next hop address was previously unset) */
DEBUG(" %p is an exact match\n", (void *)tmp);
if (next_hop != NULL) {
memcpy(&tmp_node->ipv6, next_hop, sizeof(tmp_node->ipv6));
if (tmp->mode == _EMPTY) {
if (dst == NULL) {
dst = tmp;
}
continue;
}

/* else: offlink entry not empty, potential match */
if (tmp->pfx_len == pfx_len && ipv6_addr_match_prefix(&tmp->pfx, pfx) >= pfx_len) {
/* prefix matches */
assert(tmp_node);
if (_nib_onl_get_if(tmp_node) == iface && (ipv6_addr_is_unspecified(&tmp_node->ipv6)
|| _addr_equals(next_hop, tmp_node))) {
/* next hop matches or is unspecified */
DEBUG(" %p is an exact match\n", (void *)tmp);
if (next_hop != NULL) {
/* sets next_hop if it was previously unspecified */
memcpy(&tmp_node->ipv6, next_hop, sizeof(tmp_node->ipv6));
}
/*mark that this NCE is used by an offl_entry*/
tmp->next_hop->mode |= _DST;
return tmp;
}
tmp->next_hop->mode |= _DST;
return tmp;
}
if ((dst == NULL) && (tmp_node == NULL)) {
dst = tmp;
}
}
if (dst != NULL) {
DEBUG(" using %p\n", (void *)dst);
dst->next_hop = _nib_onl_alloc(next_hop, iface);

if (dst->next_hop == NULL) {
if (!dst->next_hop && !(dst->next_hop = _nib_onl_alloc(next_hop, iface))) {
memset(dst, 0, sizeof(_nib_offl_entry_t));
return NULL;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,60 @@
TEST_ASSERT(ipv6_addr_equal(&next_hop, &dst1->next_hop->ipv6));
}

/*
* Creates an off-link entry (to a next hop) and an on-link entry on the same interface.
* Then proceeds to delete the off-link entries to this next hop
* by only comparing the next hop, not checking the _PFX_ON_LINK flag.
*
* Expected results: Only off-link entries are deleted.
* On-link entries on the same interface are unaffected by the deletion.
*/
static void test_nib_offl_alloc__next_hop_indicates_whether_onl(void)
{
static const ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
{ .u64 = TEST_UINT64 } } };
static const ipv6_addr_t pfx = { .u64 = { { .u8 = GLOBAL_PREFIX } } };

/*are in practice different prefixes actually*/
static const ipv6_addr_t *onl_pfx = &pfx;
static const ipv6_addr_t *offl_pfx = &pfx;

/* Add off-link entry */
_nib_offl_entry_t *dst1;
TEST_ASSERT_NOT_NULL((dst1 = _nib_ft_add(&next_hop, IFACE, offl_pfx, GLOBAL_PREFIX_LEN)));

/* Add on-link entry */
const unsigned pfx_len = GLOBAL_PREFIX_LEN; /* arbitrary */

/* (calls _nib_offl_alloc) */
_nib_offl_entry_t *dst;
TEST_ASSERT_NOT_NULL((dst = _nib_pl_add(IFACE, onl_pfx, pfx_len, UINT32_MAX, UINT32_MAX)));
TEST_ASSERT(ipv6_addr_is_unspecified(&dst->next_hop->ipv6));
/* would normally be set by PIO flags in Router Advertisement */
dst->flags |= _PFX_ON_LINK;

/* Delete all off-link entries to next_hop */
_nib_offl_entry_t *route = NULL;
while ((route = _nib_offl_iter(route))) {
if ((_nib_onl_get_if(route->next_hop) == IFACE) &&
(route->next_hop != NULL) &&
ipv6_addr_equal(&route->next_hop->ipv6, &next_hop) /*off-link, to this next hop*/
/*should not need to be checked for when next hop is already checked:*/
/*&& !(route->flags & _PFX_ON_LINK)*/
) {
_nib_ft_remove(route);
}
}

/* Expected result: On-link entries remain unaffected */
gnrc_ipv6_nib_pl_t prefix;
void *state = NULL;
TEST_ASSERT_MESSAGE(gnrc_ipv6_nib_pl_iter(IFACE, &state, &prefix),
"No prefix list entry found");
TEST_ASSERT_MESSAGE(ipv6_addr_match_prefix(onl_pfx, &prefix.pfx) >= pfx_len,
"Unexpected prefix configured");
}

/*
* Creates an off-link entry.
* Expected result: new entry should contain the given prefix, address and
Expand Down Expand Up @@ -2069,6 +2123,7 @@
new_TestFixture(test_nib_offl_alloc__no_space_left_diff_next_hop_iface_pfx_pfx_len),
new_TestFixture(test_nib_offl_alloc__success_duplicate),
new_TestFixture(test_nib_offl_alloc__success_overwrite_unspecified),
new_TestFixture(test_nib_offl_alloc__next_hop_indicates_whether_onl),
new_TestFixture(test_nib_offl_alloc__success),
new_TestFixture(test_nib_offl_clear__uncleared),
new_TestFixture(test_nib_offl_clear__same_next_hop),
Expand Down Expand Up @@ -2106,4 +2161,4 @@
fixtures);

return (Test *)&tests;
}

Check warning on line 2164 in tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-internal.c

View workflow job for this annotation

GitHub Actions / static-tests

source file is too long
Loading