mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #7253 from miri64/gnrc_ipv6_nib/feat/ft-component
gnrc_ipv6_nib: add forwarding table component
This commit is contained in:
commit
d5c964415b
@ -23,6 +23,7 @@
|
||||
#define NET_GNRC_IPV6_NIB_H
|
||||
|
||||
#include "net/gnrc/ipv6/nib/abr.h"
|
||||
#include "net/gnrc/ipv6/nib/ft.h"
|
||||
#include "net/gnrc/ipv6/nib/nc.h"
|
||||
#include "net/gnrc/ipv6/nib/pl.h"
|
||||
|
||||
|
148
sys/include/net/gnrc/ipv6/nib/ft.h
Normal file
148
sys/include/net/gnrc/ipv6/nib/ft.h
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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_ft Forwarding table
|
||||
* @ingroup net_gnrc_ipv6_nib
|
||||
* @brief
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Forwarding table definitions
|
||||
*
|
||||
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
#ifndef NET_GNRC_IPV6_NIB_FT_H
|
||||
#define NET_GNRC_IPV6_NIB_FT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "net/gnrc/pkt.h"
|
||||
#include "net/ipv6/addr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Forwarding table entry view on NIB
|
||||
*/
|
||||
typedef struct {
|
||||
ipv6_addr_t dst; /**< destination or prefix */
|
||||
ipv6_addr_t next_hop; /**< next hop to gnrc_ipv6_nib_ft_t::dst */
|
||||
uint8_t dst_len; /**< prefix-length in bits of
|
||||
* gnrc_ipv6_nib_ft_t::dst */
|
||||
uint8_t primary; /**< != 0 if gnrc_ipv6_nib_ft_t::dst is preferred
|
||||
* default route */
|
||||
uint16_t iface; /**< interface to gnrc_ipv6_nib_ft_t::next_hop */
|
||||
} gnrc_ipv6_nib_ft_t;
|
||||
|
||||
/**
|
||||
* @brief Gets the best matching forwarding table entry to a destination
|
||||
*
|
||||
* @pre `(dst != NULL) && (fte != NULL)`
|
||||
*
|
||||
* @param[in] dst The destination.
|
||||
* @param[in] pkt Packet that is supposed to go to that destination
|
||||
* (is handed over to a reactive routing protocol if one exists
|
||||
* on the interface found and no route is found)
|
||||
* @param[out] fte The resulting forwarding table entry.
|
||||
*
|
||||
* @return 0, on success.
|
||||
* @return -ENETUNREACH, if no route was found.
|
||||
*/
|
||||
int gnrc_ipv6_nib_ft_get(const ipv6_addr_t *dst, gnrc_pktsnip_t *pkt,
|
||||
gnrc_ipv6_nib_ft_t *fte);
|
||||
|
||||
/**
|
||||
* @brief Adds a new route to the forwarding table
|
||||
*
|
||||
* @param[in] dst The destination to the route. May be NULL or `::` for
|
||||
* default route.
|
||||
* @param[in] dst_len The prefix length of @p dst in bits. May be 0 for
|
||||
* default route.
|
||||
* @param[in] next_hop The next hop to @p dst/@p dst_len. May be NULL, if
|
||||
* @p dst/@p dst_len is no the default route.
|
||||
* @param[in] iface The interface to @p next_hop. May not be 0.
|
||||
*
|
||||
* @return 0, on success.
|
||||
* @return -EINVAL, if a parameter was of invalid value.
|
||||
* @return -ENOMEM, if there was no space left in forwarding table.
|
||||
*/
|
||||
int gnrc_ipv6_nib_ft_add(const ipv6_addr_t *dst, unsigned dst_len,
|
||||
const ipv6_addr_t *next_hop, unsigned iface);
|
||||
|
||||
/**
|
||||
* @brief Deletes a route from forwarding table.
|
||||
*
|
||||
* @param[in] dst The destination of the route. May be NULL or `::` for
|
||||
* default route.
|
||||
* @param[in] dst_len The prefix length of @p dst in bits. May be 0 for
|
||||
* default route.
|
||||
*/
|
||||
void gnrc_ipv6_nib_ft_del(const ipv6_addr_t *dst, unsigned dst_len);
|
||||
|
||||
/**
|
||||
* @brief Iterates over all forwarding table entries in the NIB
|
||||
*
|
||||
* @pre `(state != NULL) && (fte != NULL)`
|
||||
*
|
||||
* @param[in] next_hop Restrict iteration to entries to this next hop. NULL
|
||||
* for any next hop. Can be used to build a source
|
||||
* routing tree.
|
||||
* @param[in] iface Restrict iteration to entries on this interface.
|
||||
* 0 for any interface.
|
||||
* @param[in,out] state Iteration state of the forwarding table. Must point
|
||||
* to a NULL pointer to start iteration.
|
||||
* @param[out] fte The next forwarding table entry.
|
||||
*
|
||||
* The iteration over all forwarding table entries in the NIB includes all
|
||||
* entries added via @p gnrc_ipv6_nib_ft_add() and entries that are currently
|
||||
* in the Destination Cache, in the Prefix List, and in the Default Router List.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
|
||||
* #include "net/gnrc/ipv6/nib/ft.h"
|
||||
*
|
||||
* int main(void) {
|
||||
* void *state = NULL;
|
||||
* gnrc_ipv6_nib_ft_t fte;
|
||||
*
|
||||
* puts("My neighbors:");
|
||||
* while (gnrc_ipv6_nib_ft_iter(NULL, 0, &state, &fte)) {
|
||||
* gnrc_ipv6_nib_ft_print(&fte);
|
||||
* }
|
||||
* return 0;
|
||||
* }
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* @note The list may change during iteration.
|
||||
*
|
||||
* @return true, if iteration can be continued.
|
||||
* @return false, if @p fte is the last neighbor cache entry in the NIB.
|
||||
*/
|
||||
bool gnrc_ipv6_nib_ft_iter(const ipv6_addr_t *next_hop, unsigned iface,
|
||||
void **state, gnrc_ipv6_nib_ft_t *fte);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Prints a forwarding table entry
|
||||
*
|
||||
* @pre `fce != NULL`
|
||||
*
|
||||
* @param[in] fte A forwarding table entry.
|
||||
*/
|
||||
void gnrc_ipv6_nib_ft_print(const gnrc_ipv6_nib_ft_t *fte);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_GNRC_IPV6_NIB_FT_H */
|
||||
/** @} */
|
@ -401,6 +401,18 @@ _nib_dr_entry_t *_nib_drl_get_dr(void)
|
||||
return _prime_def_router;
|
||||
}
|
||||
|
||||
void _nib_drl_ft_get(const _nib_dr_entry_t *drl, gnrc_ipv6_nib_ft_t *fte)
|
||||
{
|
||||
assert((drl != NULL) && (drl->next_hop != NULL) && (fte != NULL));
|
||||
ipv6_addr_set_unspecified(&fte->dst);
|
||||
fte->dst_len = 0;
|
||||
fte->primary = ((drl == _prime_def_router) &&
|
||||
!((_prime_def_router == NULL) ||
|
||||
(_node_unreachable(_prime_def_router->next_hop))));
|
||||
memcpy(&fte->next_hop, &drl->next_hop->ipv6, sizeof(fte->next_hop));
|
||||
fte->iface = _nib_onl_get_if(drl->next_hop);
|
||||
}
|
||||
|
||||
_nib_offl_entry_t *_nib_offl_alloc(const ipv6_addr_t *next_hop, unsigned iface,
|
||||
const ipv6_addr_t *pfx, unsigned pfx_len)
|
||||
{
|
||||
@ -497,6 +509,87 @@ _nib_offl_entry_t *_nib_offl_iter(const _nib_offl_entry_t *last)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool _nib_offl_is_entry(const _nib_offl_entry_t *entry)
|
||||
{
|
||||
return (entry >= _dsts) && _in_dsts(entry);
|
||||
}
|
||||
|
||||
static _nib_offl_entry_t *_nib_offl_get_match(const ipv6_addr_t *dst)
|
||||
{
|
||||
_nib_offl_entry_t *res = NULL;
|
||||
uint8_t best_match = 0;
|
||||
|
||||
DEBUG("nib: get match for destination %s from NIB\n",
|
||||
ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)));
|
||||
for (_nib_offl_entry_t *entry = _dsts; _in_dsts(entry); entry++) {
|
||||
if (entry->mode != _EMPTY) {
|
||||
uint8_t match = ipv6_addr_match_prefix(&entry->pfx, dst);
|
||||
|
||||
DEBUG("nib: %s/%u => ",
|
||||
ipv6_addr_to_str(addr_str, &entry->pfx, sizeof(addr_str)),
|
||||
entry->pfx_len);
|
||||
DEBUG("%s%%%u matches with %u bits\n",
|
||||
(entry->mode == _PL) ? "(nil)" :
|
||||
ipv6_addr_to_str(addr_str, &entry->next_hop->ipv6,
|
||||
sizeof(addr_str)),
|
||||
_nib_onl_get_if(entry->next_hop), match);
|
||||
if ((match > best_match) && (match >= entry->pfx_len)) {
|
||||
DEBUG("nib: best match (%u bits)\n", match);
|
||||
res = entry;
|
||||
best_match = match;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void _nib_ft_get(const _nib_offl_entry_t *dst, gnrc_ipv6_nib_ft_t *fte)
|
||||
{
|
||||
assert((dst != NULL) && (dst->next_hop != NULL) && (fte != NULL));
|
||||
memcpy(&fte->dst, &dst->pfx, sizeof(dst->pfx));
|
||||
fte->dst_len = dst->pfx_len;
|
||||
fte->primary = 0;
|
||||
fte->iface = _nib_onl_get_if(dst->next_hop);
|
||||
if (dst->mode == _PL) { /* entry is only in prefix list */
|
||||
ipv6_addr_set_unspecified(&fte->next_hop);
|
||||
}
|
||||
else {
|
||||
memcpy(&fte->next_hop, &dst->next_hop->ipv6, sizeof(dst->next_hop->ipv6));
|
||||
}
|
||||
}
|
||||
|
||||
int _nib_get_route(const ipv6_addr_t *dst, gnrc_pktsnip_t *pkt,
|
||||
gnrc_ipv6_nib_ft_t *fte)
|
||||
{
|
||||
assert((dst != NULL) && (fte != NULL));
|
||||
DEBUG("nib: get route %s for packet %p\n",
|
||||
ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)),
|
||||
(void *)pkt);
|
||||
_nib_offl_entry_t *offl = _nib_offl_get_match(dst);
|
||||
|
||||
assert((dst != NULL) && (fte != NULL));
|
||||
if ((offl == NULL) || (offl->mode == _PL)) {
|
||||
/* give default router precedence over PLE */
|
||||
_nib_dr_entry_t *router = _nib_drl_get_dr();
|
||||
|
||||
if ((router == NULL) && (offl == NULL)) {
|
||||
(void)pkt;
|
||||
/* TODO: ask RRP to search for route (using pkt) */
|
||||
return -ENETUNREACH;
|
||||
}
|
||||
else if (router != NULL) {
|
||||
DEBUG("nib: prefer default router %s%%%u over prefix list entry\n",
|
||||
ipv6_addr_to_str(addr_str, &router->next_hop->ipv6,
|
||||
sizeof(addr_str)),
|
||||
_nib_onl_get_if(router->next_hop));
|
||||
_nib_drl_ft_get(router, fte);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
_nib_ft_get(offl, fte);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _nib_pl_remove(_nib_offl_entry_t *nib_offl)
|
||||
{
|
||||
_nib_offl_remove(nib_offl, _PL);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#endif
|
||||
#include "net/gnrc/ipv6/nib/ft.h"
|
||||
#include "net/gnrc/ipv6/nib/nc.h"
|
||||
#include "net/gnrc/ipv6/nib/conf.h"
|
||||
#include "net/gnrc/pktqueue.h"
|
||||
@ -463,6 +464,17 @@ _nib_dr_entry_t *_nib_drl_iter(const _nib_dr_entry_t *last);
|
||||
*/
|
||||
_nib_dr_entry_t *_nib_drl_get(const ipv6_addr_t *router_addr, unsigned iface);
|
||||
|
||||
/**
|
||||
* @brief Gets external forwarding table entry representation from default
|
||||
* router entry
|
||||
*
|
||||
* @pre `(drl != NULL) && (drl->next_hop != NULL) && (fte != NULL)`
|
||||
*
|
||||
* @param[in] drl Default router entry.
|
||||
* @param[out] fte External representation of the forwarding table entry.
|
||||
*/
|
||||
void _nib_drl_ft_get(const _nib_dr_entry_t *drl, gnrc_ipv6_nib_ft_t *fte);
|
||||
|
||||
/**
|
||||
* @brief Gets *the* default router
|
||||
*
|
||||
@ -509,6 +521,16 @@ void _nib_offl_clear(_nib_offl_entry_t *dst);
|
||||
*/
|
||||
_nib_offl_entry_t *_nib_offl_iter(const _nib_offl_entry_t *last);
|
||||
|
||||
/**
|
||||
* @brief Checks if @p entry was allocated using _nib_offl_alloc()
|
||||
*
|
||||
* @param[in] entry An entry.
|
||||
*
|
||||
* @return true, if @p entry was allocated using @ref _nib_offl_alloc()
|
||||
* @return false, if @p entry was not allocated using @ref _nib_offl_alloc()
|
||||
*/
|
||||
bool _nib_offl_is_entry(const _nib_offl_entry_t *entry);
|
||||
|
||||
/**
|
||||
* @brief Helper function for view-level add-functions below
|
||||
*
|
||||
@ -726,6 +748,34 @@ _nib_offl_entry_t *_nib_abr_iter_pfx(const _nib_abr_entry_t *abr,
|
||||
_nib_abr_entry_t *_nib_abr_iter(const _nib_abr_entry_t *last);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Gets external forwarding table entry representation from off-link
|
||||
* entry
|
||||
*
|
||||
* @pre `(dst != NULL) && (dst->next_hop != NULL) && (fte != NULL)`
|
||||
*
|
||||
* @param[in] dst Off-link entry.
|
||||
* @param[out] fte External representation of the forwarding table entry.
|
||||
*/
|
||||
void _nib_ft_get(const _nib_offl_entry_t *dst, gnrc_ipv6_nib_ft_t *fte);
|
||||
|
||||
/**
|
||||
* @brief Gets best match to @p dst from all off-link entries and default
|
||||
* route.
|
||||
*
|
||||
* @pre `(dst != NULL) && (fte != NULL)`
|
||||
*
|
||||
* @param[in] dst Destination address to get the off-link entry for.
|
||||
* @param[in] pkt Packet causing the route look-up (provided to allow reactive
|
||||
* routing protocols to queue it if needed). May be NULL.
|
||||
* @param[out] fte Resulting forwarding table entry.
|
||||
*
|
||||
* @return 0, on success.
|
||||
* @return -ENETUNREACH, when no route was found.
|
||||
*/
|
||||
int _nib_get_route(const ipv6_addr_t *dst, gnrc_pktsnip_t *ctx,
|
||||
gnrc_ipv6_nib_ft_t *entry);
|
||||
|
||||
/**
|
||||
* @brief Gets (or creates if it not exists) interface information for
|
||||
* neighbor discovery
|
||||
|
146
sys/net/gnrc/network_layer/ipv6/nib/nib_ft.c
Normal file
146
sys/net/gnrc/network_layer/ipv6/nib/nib_ft.c
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "_nib-internal.h"
|
||||
|
||||
#include "net/gnrc/ipv6/nib/ft.h"
|
||||
|
||||
int gnrc_ipv6_nib_ft_get(const ipv6_addr_t *dst, gnrc_pktsnip_t *pkt,
|
||||
gnrc_ipv6_nib_ft_t *fte)
|
||||
{
|
||||
int res;
|
||||
|
||||
assert((dst != NULL) && (fte != NULL));
|
||||
mutex_lock(&_nib_mutex);
|
||||
res = _nib_get_route(dst, pkt, fte);
|
||||
mutex_unlock(&_nib_mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
int gnrc_ipv6_nib_ft_add(const ipv6_addr_t *dst, unsigned dst_len,
|
||||
const ipv6_addr_t *next_hop, unsigned iface)
|
||||
{
|
||||
void *ptr = NULL;
|
||||
int res = 0;
|
||||
bool is_default_route = ((dst == NULL) || (dst_len == 0) ||
|
||||
ipv6_addr_is_unspecified(dst));
|
||||
|
||||
if ((iface == 0) || ((is_default_route) && (next_hop == NULL))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock(&_nib_mutex);
|
||||
if (is_default_route) {
|
||||
ptr = _nib_drl_add(next_hop, iface);
|
||||
}
|
||||
#if GNRC_IPV6_NIB_CONF_ROUTER
|
||||
else {
|
||||
dst_len = (dst_len > 128) ? 128 : dst_len;
|
||||
ptr = _nib_ft_add(next_hop, iface, dst, dst_len);
|
||||
}
|
||||
#else /* GNRC_IPV6_NIB_CONF_ROUTER */
|
||||
else {
|
||||
res = -ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
mutex_unlock(&_nib_mutex);
|
||||
if (ptr == NULL) {
|
||||
res = -ENOMEM;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void gnrc_ipv6_nib_ft_del(const ipv6_addr_t *dst, unsigned dst_len)
|
||||
{
|
||||
mutex_lock(&_nib_mutex);
|
||||
if ((dst == NULL) || (dst_len == 0) || ipv6_addr_is_unspecified(dst)) {
|
||||
_nib_dr_entry_t *entry = _nib_drl_get_dr();
|
||||
|
||||
if (entry != NULL) {
|
||||
_nib_drl_remove(entry);
|
||||
}
|
||||
}
|
||||
#if GNRC_IPV6_NIB_CONF_ROUTER
|
||||
else {
|
||||
_nib_offl_entry_t *entry = NULL;
|
||||
|
||||
while ((entry = _nib_offl_iter(entry))) {
|
||||
if ((entry->pfx_len == dst_len) &&
|
||||
(ipv6_addr_match_prefix(&entry->pfx, dst) >= dst_len)) {
|
||||
_nib_ft_remove(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mutex_unlock(&_nib_mutex);
|
||||
}
|
||||
|
||||
bool gnrc_ipv6_nib_ft_iter(const ipv6_addr_t *next_hop, unsigned iface,
|
||||
void **state, gnrc_ipv6_nib_ft_t *fte)
|
||||
{
|
||||
_nib_dr_entry_t *entry;
|
||||
assert((state != NULL) && (fte != NULL));
|
||||
|
||||
if ((*state == NULL) || _nib_offl_is_entry(*state)) {
|
||||
_nib_offl_entry_t *offl = *state;
|
||||
|
||||
while ((offl = _nib_offl_iter(offl))) {
|
||||
assert((offl->mode != 0) || (offl->next_hop != NULL));
|
||||
if (((iface == 0) || (iface == _nib_onl_get_if(offl->next_hop))) &&
|
||||
((next_hop == NULL) || ipv6_addr_equal(&offl->next_hop->ipv6,
|
||||
next_hop))) {
|
||||
_nib_ft_get(offl, fte);
|
||||
*state = offl;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
*state = NULL;
|
||||
}
|
||||
entry = *state;
|
||||
while ((entry = _nib_drl_iter(entry))) {
|
||||
assert((entry->next_hop != NULL));
|
||||
if (((iface == 0) || (iface == _nib_onl_get_if(entry->next_hop))) &&
|
||||
((next_hop == NULL) || ipv6_addr_equal(&entry->next_hop->ipv6,
|
||||
next_hop))) {
|
||||
_nib_drl_ft_get(entry, fte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*state = entry;
|
||||
return (*state != NULL);
|
||||
}
|
||||
|
||||
void gnrc_ipv6_nib_ft_print(const gnrc_ipv6_nib_ft_t *fte)
|
||||
{
|
||||
char addr_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
|
||||
if ((fte->dst_len == 0) || ipv6_addr_is_unspecified(&fte->dst)) {
|
||||
printf("default%s ", (fte->primary ? "*" : ""));
|
||||
}
|
||||
else {
|
||||
printf("%s/%u ", ipv6_addr_to_str(addr_str, &fte->dst, sizeof(addr_str)),
|
||||
fte->dst_len);
|
||||
}
|
||||
if (!ipv6_addr_is_unspecified(&fte->next_hop)) {
|
||||
printf("via %s ", ipv6_addr_to_str(addr_str, &fte->next_hop,
|
||||
sizeof(addr_str)));
|
||||
}
|
||||
printf("dev #%u\n", fte->iface);
|
||||
}
|
||||
|
||||
/**i @} */
|
@ -22,6 +22,7 @@
|
||||
static void _usage(char **argv);
|
||||
static int _nib_neigh(int argc, char **argv);
|
||||
static int _nib_prefix(int argc, char **argv);
|
||||
static int _nib_route(int argc, char **argv);
|
||||
|
||||
int _gnrc_ipv6_nib(int argc, char **argv)
|
||||
{
|
||||
@ -37,6 +38,9 @@ int _gnrc_ipv6_nib(int argc, char **argv)
|
||||
else if (strcmp(argv[1], "prefix") == 0) {
|
||||
res = _nib_prefix(argc, argv);
|
||||
}
|
||||
else if (strcmp(argv[1], "route") == 0) {
|
||||
res = _nib_route(argc, argv);
|
||||
}
|
||||
else {
|
||||
_usage(argv);
|
||||
}
|
||||
@ -45,7 +49,7 @@ int _gnrc_ipv6_nib(int argc, char **argv)
|
||||
|
||||
static void _usage(char **argv)
|
||||
{
|
||||
printf("usage: %s {neigh|prefix|help} ...\n", argv[0]);
|
||||
printf("usage: %s {neigh|prefix|route|help} ...\n", argv[0]);
|
||||
}
|
||||
|
||||
static void _usage_nib_neigh(char **argv)
|
||||
@ -65,6 +69,15 @@ static void _usage_nib_prefix(char **argv)
|
||||
printf(" %s %s show <iface>\n", argv[0], argv[1]);
|
||||
}
|
||||
|
||||
static void _usage_nib_route(char **argv)
|
||||
{
|
||||
printf("usage: %s %s [show|add|del|help]\n", argv[0], argv[1]);
|
||||
printf(" %s %s add <iface> <prefix>[/<prefix_len>] <next_hop>\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)) {
|
||||
@ -169,4 +182,57 @@ static int _nib_prefix(int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nib_route(int argc, char **argv)
|
||||
{
|
||||
if ((argc == 2) || (strcmp(argv[2], "show") == 0)) {
|
||||
gnrc_ipv6_nib_ft_t entry;
|
||||
void *state = NULL;
|
||||
unsigned iface = 0U;
|
||||
|
||||
if (argc > 3) {
|
||||
iface = atoi(argv[3]);
|
||||
}
|
||||
while (gnrc_ipv6_nib_ft_iter(NULL, iface, &state, &entry)) {
|
||||
gnrc_ipv6_nib_ft_print(&entry);
|
||||
}
|
||||
}
|
||||
else if ((argc > 2) && (strcmp(argv[2], "help") == 0)) {
|
||||
_usage_nib_route(argv);
|
||||
}
|
||||
else if ((argc > 5) && (strcmp(argv[2], "add") == 0)) {
|
||||
ipv6_addr_t pfx = IPV6_ADDR_UNSPECIFIED, next_hop;
|
||||
unsigned iface = atoi(argv[3]);
|
||||
unsigned pfx_len = ipv6_addr_split_prefix(argv[4]);
|
||||
|
||||
if (ipv6_addr_from_str(&pfx, argv[4]) == NULL) {
|
||||
/* check if string equals "default"
|
||||
* => keep pfx as unspecified address == default route */
|
||||
if (strcmp(argv[4], "default") != 0) {
|
||||
_usage_nib_route(argv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (ipv6_addr_from_str(&next_hop, argv[5]) == NULL) {
|
||||
_usage_nib_route(argv);
|
||||
return 1;
|
||||
}
|
||||
gnrc_ipv6_nib_ft_add(&pfx, pfx_len, &next_hop, iface);
|
||||
}
|
||||
else if ((argc > 4) && (strcmp(argv[2], "del") == 0)) {
|
||||
ipv6_addr_t pfx;
|
||||
unsigned pfx_len = ipv6_addr_split_prefix(argv[4]);
|
||||
|
||||
if (ipv6_addr_from_str(&pfx, argv[4]) == NULL) {
|
||||
_usage_nib_route(argv);
|
||||
return 1;
|
||||
}
|
||||
gnrc_ipv6_nib_ft_del(&pfx, pfx_len);
|
||||
}
|
||||
else {
|
||||
_usage_nib_route(argv);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
656
tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-ft.c
Normal file
656
tests/unittests/tests-gnrc_ipv6_nib/tests-gnrc_ipv6_nib-ft.c
Normal file
@ -0,0 +1,656 @@
|
||||
/*
|
||||
* 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 "bitfield.h"
|
||||
#include "net/ipv6/addr.h"
|
||||
#include "net/gnrc/ipv6/nib.h"
|
||||
#include "net/gnrc/ipv6/nib/ft.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)
|
||||
{
|
||||
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 get a route from an empty forwarding table.
|
||||
* Expected result: gnrc_ipv6_nib_ft_get() returns -ENETUNREACH
|
||||
*/
|
||||
static void test_nib_ft_get__ENETUNREACH_empty(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t fte;
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(-ENETUNREACH, gnrc_ipv6_nib_ft_get(&dst, NULL, &fte));
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a route (not the default route) to the forwarding table, then tries to
|
||||
* get another route.
|
||||
* Expected result: gnrc_ipv6_nib_ft_get() returns -ENETUNREACH
|
||||
*/
|
||||
static void test_nib_ft_get__ENETUNREACH_no_def_route(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t fte;
|
||||
static const ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, IFACE));
|
||||
dst.u16[0].u16--;
|
||||
TEST_ASSERT_EQUAL_INT(-ENETUNREACH, gnrc_ipv6_nib_ft_get(&dst, NULL, &fte));
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds the default route to the forwarding table, then tries to get an
|
||||
* arbitrary route.
|
||||
* Expected result: gnrc_ipv6_nib_ft_get() returns the configured default route
|
||||
*/
|
||||
static void test_nib_ft_get__success1(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t fte;
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
static const ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(NULL, 0, &next_hop, IFACE));
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_get(&dst, NULL, &fte));
|
||||
TEST_ASSERT(ipv6_addr_is_unspecified(&fte.dst));
|
||||
TEST_ASSERT(ipv6_addr_equal(&next_hop, &fte.next_hop));
|
||||
TEST_ASSERT_EQUAL_INT(0, fte.dst_len);
|
||||
/* we can't make any sure assumption on fte.primary */
|
||||
TEST_ASSERT_EQUAL_INT(IFACE, fte.iface);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds an arbitrary route to the forwarding table, then tries to get an address
|
||||
* with the same prefix.
|
||||
* Expected result: gnrc_ipv6_nib_ft_get() returns the configured route
|
||||
*/
|
||||
static void test_nib_ft_get__success2(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t fte;
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
static const ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, IFACE));
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_get(&dst, NULL, &fte));
|
||||
TEST_ASSERT(ipv6_addr_match_prefix(&dst, &fte.dst) >= GLOBAL_PREFIX_LEN);
|
||||
TEST_ASSERT(ipv6_addr_equal(&next_hop, &fte.next_hop));
|
||||
TEST_ASSERT_EQUAL_INT(GLOBAL_PREFIX_LEN, fte.dst_len);
|
||||
/* we can't make any sure assumption on fte.primary */
|
||||
TEST_ASSERT_EQUAL_INT(IFACE, fte.iface);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds two routes to the forwarding table that differ in their last byte
|
||||
* (prefixes have same length), then tries to get an address with the same
|
||||
* prefix as the first route.
|
||||
* Expected result: gnrc_ipv6_nib_ft_get() returns the first configured route
|
||||
*/
|
||||
static void test_nib_ft_get__success3(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t fte;
|
||||
static const ipv6_addr_t dst1 = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
static const ipv6_addr_t next_hop1 = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
static const ipv6_addr_t next_hop2 = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 + 1 } } };
|
||||
ipv6_addr_t dst2 = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
|
||||
bf_toggle(dst2.u8, GLOBAL_PREFIX_LEN);
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst1, GLOBAL_PREFIX_LEN,
|
||||
&next_hop1, IFACE));
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst2, GLOBAL_PREFIX_LEN,
|
||||
&next_hop2, IFACE));
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_get(&dst1, NULL, &fte));
|
||||
TEST_ASSERT(ipv6_addr_match_prefix(&dst1, &fte.dst) >= GLOBAL_PREFIX_LEN);
|
||||
TEST_ASSERT(ipv6_addr_equal(&next_hop1, &fte.next_hop));
|
||||
TEST_ASSERT_EQUAL_INT(GLOBAL_PREFIX_LEN, fte.dst_len);
|
||||
/* we can't make any sure assumption on fte.primary */
|
||||
TEST_ASSERT_EQUAL_INT(IFACE, fte.iface);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds two routes to the forwarding table that only differ in their prefix
|
||||
* length by one bit me length, then tries to get an address with the same
|
||||
* prefix as the route with the longer prefix.
|
||||
* Expected result: gnrc_ipv6_nib_ft_get() returns route with the longer prefix
|
||||
*/
|
||||
static void test_nib_ft_get__success4(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t fte;
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
static const ipv6_addr_t next_hop1 = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
static const ipv6_addr_t next_hop2 = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 + 1 } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop1, IFACE));
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN - 1,
|
||||
&next_hop2, IFACE));
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_get(&dst, NULL, &fte));
|
||||
TEST_ASSERT(ipv6_addr_match_prefix(&dst, &fte.dst) >= GLOBAL_PREFIX_LEN);
|
||||
TEST_ASSERT(ipv6_addr_equal(&next_hop1, &fte.next_hop));
|
||||
TEST_ASSERT_EQUAL_INT(GLOBAL_PREFIX_LEN, fte.dst_len);
|
||||
/* we can't make any sure assumption on fte.primary */
|
||||
TEST_ASSERT_EQUAL_INT(IFACE, fte.iface);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to create a forwarding table entry for the default route (::) with
|
||||
* NULL as next hop.
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -EINVAL
|
||||
*/
|
||||
static void test_nib_ft_add__EINVAL_def_route_next_hop_NULL(void)
|
||||
{
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, gnrc_ipv6_nib_ft_add(&ipv6_addr_unspecified,
|
||||
GLOBAL_PREFIX_LEN,
|
||||
NULL, IFACE));
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, gnrc_ipv6_nib_ft_add(NULL, GLOBAL_PREFIX_LEN,
|
||||
NULL, IFACE));
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, gnrc_ipv6_nib_ft_add(&dst, 0, NULL, IFACE));
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, gnrc_ipv6_nib_ft_add(NULL, 0, NULL, IFACE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to create a route via interface 0.
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -EINVAL
|
||||
*/
|
||||
static void test_nib_ft_add__EINVAL_iface0(void)
|
||||
{
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
static const ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(-EINVAL, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, 0));
|
||||
}
|
||||
|
||||
#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 GNRC_IPV6_NIB_DEFAULT_ROUTER_NUMOF default route entries and then
|
||||
* tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_def_router(void)
|
||||
{
|
||||
ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
for (unsigned i = 0; i < GNRC_IPV6_NIB_DEFAULT_ROUTER_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(NULL, 0, &next_hop,
|
||||
IFACE));
|
||||
next_hop.u64[1].u64++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(NULL, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, IFACE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates GNRC_IPV6_NIB_OFFL_NUMOF routes with different destinations of same
|
||||
* prefix lengths to the same next hop and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_dst(void)
|
||||
{
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
|
||||
for (unsigned i = 0; i < GNRC_IPV6_NIB_OFFL_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
NULL, IFACE));
|
||||
dst.u16[0].u16--;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
NULL, IFACE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates GNRC_IPV6_NIB_OFFL_NUMOF routes with destinations of different
|
||||
* prefix lengths to the same next hop and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_dst_len(void)
|
||||
{
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
unsigned dst_len = GLOBAL_PREFIX_LEN;
|
||||
|
||||
for (unsigned i = 0; i < GNRC_IPV6_NIB_OFFL_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
NULL, IFACE));
|
||||
dst_len--;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
NULL, IFACE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates GNRC_IPV6_NIB_OFFL_NUMOF routes with different destination of
|
||||
* different prefix lengths to the same next hop and then tries to create
|
||||
* another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_dst_dst_len(void)
|
||||
{
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
unsigned dst_len = GLOBAL_PREFIX_LEN;
|
||||
|
||||
for (unsigned i = 0; i < GNRC_IPV6_NIB_OFFL_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
NULL, IFACE));
|
||||
dst.u16[0].u16--;
|
||||
dst_len--;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
NULL, IFACE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with the same destination different next hops and
|
||||
* then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_next_hop(void)
|
||||
{
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, IFACE));
|
||||
next_hop.u64[1].u64++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, IFACE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with different destinations of same prefix lengths
|
||||
* to the different next hops and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_dst_next_hop(void)
|
||||
{
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, IFACE));
|
||||
dst.u16[0].u16--;
|
||||
next_hop.u64[1].u64++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, IFACE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with different destinations of same prefix lengths
|
||||
* to different next hops and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_dst_dst_len_next_hop(void)
|
||||
{
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned dst_len = GLOBAL_PREFIX_LEN;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, dst_len, &next_hop,
|
||||
IFACE));
|
||||
dst.u16[0].u16--;
|
||||
dst_len--;
|
||||
next_hop.u64[1].u64++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
&next_hop, IFACE));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with different destinations of same prefix lengths
|
||||
* to the same next hop but on different interfaces and then tries to create
|
||||
* another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_dst_iface(void)
|
||||
{
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
unsigned iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
NULL, iface));
|
||||
dst.u16[0].u16--;
|
||||
iface++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
NULL, iface));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with destinations of different prefix lengths to the
|
||||
* same next hop but on different interfaces and then tries to create another
|
||||
* one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_dst_len_iface(void)
|
||||
{
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
unsigned dst_len = GLOBAL_PREFIX_LEN;
|
||||
unsigned iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
NULL, iface));
|
||||
dst_len--;
|
||||
iface++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
NULL, iface));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with different destination of different prefix
|
||||
* lengths to the same next hop but on different interfaces and then tries to
|
||||
* create another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_dst_dst_len_iface(void)
|
||||
{
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
unsigned dst_len = GLOBAL_PREFIX_LEN;
|
||||
unsigned iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
NULL, iface));
|
||||
dst.u16[0].u16--;
|
||||
dst_len--;
|
||||
iface++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
NULL, iface));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with the same destination to different next hops and
|
||||
* interfaces and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_next_hop_iface(void)
|
||||
{
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, iface));
|
||||
next_hop.u64[1].u64++;
|
||||
iface++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, iface));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with different destinations of same prefix lengths
|
||||
* to different next hops and interfaces and then tries to create another one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_dst_next_hop_iface(void)
|
||||
{
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, iface));
|
||||
dst.u16[0].u16--;
|
||||
next_hop.u64[1].u64++;
|
||||
iface++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, iface));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with different destinations of same prefix lengths
|
||||
* to the different next hops and interfaces and then tries to create another
|
||||
* one
|
||||
* Expected result: gnrc_ipv6_nib_ft_add() returns -ENOMEM
|
||||
*/
|
||||
static void test_nib_ft_add__ENOMEM_diff_dst_dst_len_next_hop_iface(void)
|
||||
{
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned dst_len = GLOBAL_PREFIX_LEN;
|
||||
unsigned iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, dst_len, &next_hop,
|
||||
iface));
|
||||
dst.u16[0].u16--;
|
||||
dst_len--;
|
||||
next_hop.u64[1].u64++;
|
||||
iface++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(-ENOMEM, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
&next_hop, iface));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with different destinations to different next hops
|
||||
* and interfaces and then tries add another equal to the last.
|
||||
* Expected result: should return not NULL (the last)
|
||||
*/
|
||||
static void test_nib_ft_add__success_duplicate(void)
|
||||
{
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned dst_len = GLOBAL_PREFIX_LEN;
|
||||
unsigned iface = IFACE;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
dst.u16[0].u16--;
|
||||
dst_len--;
|
||||
next_hop.u64[1].u64++;
|
||||
iface++;
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, dst_len, &next_hop,
|
||||
iface));
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, dst_len,
|
||||
&next_hop, iface));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a route with no next hop address then adds another with equal prefix
|
||||
* and interface to the last, but with a next hop address
|
||||
* Expected result: there should only be one route (with the configuration of
|
||||
* the second)
|
||||
*/
|
||||
static void test_nib_ft_add__success_overwrite_unspecified(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t fte;
|
||||
void *iter_state = NULL;
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
static const ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN, NULL,
|
||||
IFACE));
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, IFACE));
|
||||
TEST_ASSERT(gnrc_ipv6_nib_ft_iter(NULL, 0, &iter_state, &fte));
|
||||
TEST_ASSERT(ipv6_addr_equal(&fte.next_hop, &next_hop));
|
||||
TEST_ASSERT(!gnrc_ipv6_nib_ft_iter(NULL, 0, &iter_state, &fte));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a route
|
||||
* Expected result: a new entry should exist and contain the given prefix,
|
||||
* interface, and lifetimes
|
||||
*/
|
||||
static void test_nib_ft_add__success(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t fte;
|
||||
void *iter_state = NULL;
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
static const ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, IFACE));
|
||||
TEST_ASSERT(gnrc_ipv6_nib_ft_iter(NULL, 0, &iter_state, &fte));
|
||||
TEST_ASSERT(ipv6_addr_match_prefix(&fte.dst, &dst) >= GLOBAL_PREFIX_LEN);
|
||||
TEST_ASSERT_EQUAL_INT(GLOBAL_PREFIX_LEN, fte.dst_len);
|
||||
TEST_ASSERT(ipv6_addr_equal(&fte.next_hop, &next_hop));
|
||||
TEST_ASSERT_EQUAL_INT(IFACE, fte.iface);
|
||||
TEST_ASSERT_EQUAL_INT(0, fte.primary);
|
||||
TEST_ASSERT(!gnrc_ipv6_nib_ft_iter(NULL, 0, &iter_state, &fte));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates MAX_NUMOF routes with different destinations of to the different
|
||||
* next hops and interfaces and then tries to delete one with yet another
|
||||
* destination, next hop and interface.
|
||||
* Expected result: There should be still MAX_NUMOF entries in the forwarding
|
||||
* table
|
||||
*/
|
||||
static void test_nib_ft_del__unknown(void)
|
||||
{
|
||||
gnrc_ipv6_nib_ft_t fte;
|
||||
void *iter_state = NULL;
|
||||
ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
unsigned dst_len = GLOBAL_PREFIX_LEN, iface = IFACE, count = 0;
|
||||
|
||||
for (unsigned i = 0; i < MAX_NUMOF; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, dst_len, &next_hop,
|
||||
iface));
|
||||
dst.u16[0].u16--;
|
||||
dst_len--;
|
||||
next_hop.u64[1].u64++;
|
||||
iface++;
|
||||
}
|
||||
gnrc_ipv6_nib_ft_del(&dst, dst_len);
|
||||
while(gnrc_ipv6_nib_ft_iter(NULL, 0, &iter_state, &fte)) {
|
||||
count++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(MAX_NUMOF, count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a route and removes it.
|
||||
* Expected result: forwarding table should be empty
|
||||
*/
|
||||
static void test_nib_ft_del__success(void)
|
||||
{
|
||||
void *iter_state = NULL;
|
||||
static const ipv6_addr_t dst = { .u64 = { { .u8 = GLOBAL_PREFIX } } };
|
||||
static const ipv6_addr_t next_hop = { .u64 = { { .u8 = LINK_LOCAL_PREFIX },
|
||||
{ .u64 = TEST_UINT64 } } };
|
||||
gnrc_ipv6_nib_ft_t fte;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, gnrc_ipv6_nib_ft_add(&dst, GLOBAL_PREFIX_LEN,
|
||||
&next_hop, IFACE));
|
||||
gnrc_ipv6_nib_ft_del(&dst, GLOBAL_PREFIX_LEN);
|
||||
TEST_ASSERT(!gnrc_ipv6_nib_ft_iter(NULL ,0, &iter_state, &fte));
|
||||
}
|
||||
|
||||
Test *tests_gnrc_ipv6_nib_ft_tests(void)
|
||||
{
|
||||
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||
new_TestFixture(test_nib_ft_get__ENETUNREACH_empty),
|
||||
new_TestFixture(test_nib_ft_get__ENETUNREACH_no_def_route),
|
||||
new_TestFixture(test_nib_ft_get__success1),
|
||||
new_TestFixture(test_nib_ft_get__success2),
|
||||
new_TestFixture(test_nib_ft_get__success3),
|
||||
new_TestFixture(test_nib_ft_get__success4),
|
||||
new_TestFixture(test_nib_ft_add__EINVAL_def_route_next_hop_NULL),
|
||||
new_TestFixture(test_nib_ft_add__EINVAL_iface0),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_def_router),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_dst),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_dst_len),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_dst_dst_len),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_next_hop),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_dst_next_hop),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_dst_dst_len_next_hop),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_dst_iface),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_dst_len_iface),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_dst_dst_len_iface),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_next_hop_iface),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_dst_next_hop_iface),
|
||||
new_TestFixture(test_nib_ft_add__ENOMEM_diff_dst_dst_len_next_hop_iface),
|
||||
new_TestFixture(test_nib_ft_add__success_duplicate),
|
||||
new_TestFixture(test_nib_ft_add__success_overwrite_unspecified),
|
||||
new_TestFixture(test_nib_ft_add__success),
|
||||
new_TestFixture(test_nib_ft_del__unknown),
|
||||
new_TestFixture(test_nib_ft_del__success),
|
||||
/* gnrc_ipv6_nib_ft_iter() is tested during all the tests above */
|
||||
};
|
||||
|
||||
EMB_UNIT_TESTCALLER(tests, set_up, NULL,
|
||||
fixtures);
|
||||
|
||||
return (Test *)&tests;
|
||||
}
|
@ -19,6 +19,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_ft_tests());
|
||||
TESTS_RUN(tests_gnrc_ipv6_nib_nc_tests());
|
||||
TESTS_RUN(tests_gnrc_ipv6_nib_pl_tests());
|
||||
}
|
||||
|
@ -43,6 +43,13 @@ Test *tests_gnrc_ipv6_nib_internal_tests(void);
|
||||
*/
|
||||
Test *tests_gnrc_ipv6_nib_abr_tests(void);
|
||||
|
||||
/**
|
||||
* @brief Generates tests for forwarding table view
|
||||
*
|
||||
* @return embUnit tests if successful, NULL if not.
|
||||
*/
|
||||
Test *tests_gnrc_ipv6_nib_ft_tests(void);
|
||||
|
||||
/**
|
||||
* @brief Generates tests for neighbor cache view
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user