1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

net: added a core implementation of a FIB

This commit is contained in:
BytesGalore 2014-11-04 08:47:57 +01:00
parent 2fe68d5b26
commit 30c76adc43
16 changed files with 2014 additions and 0 deletions

View File

@ -150,3 +150,9 @@ ifneq (,$(filter nhdp,$(USEMODULE)))
USEMODULE += oonf_common
USEMODULE += oonf_rfc5444
endif
ifneq (,$(filter fib,$(USEMODULE)))
USEMODULE += timex
USEMODULE += vtimer
USEMODULE += net_help
endif

View File

@ -101,6 +101,9 @@ endif
ifneq (,$(filter ng_pktdump,$(USEMODULE)))
DIRS += net/crosslayer/ng_pktdump
endif
ifneq (,$(filter fib,$(USEMODULE)))
DIRS += net/network_layer/fib
endif
DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))

View File

@ -74,6 +74,10 @@ ifneq (,$(filter oneway_malloc,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/oneway-malloc/include
endif
ifneq (,$(filter fib,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/include/net
endif
ifneq (,$(filter embunit,$(USEMODULE)))
ifeq ($(OUTPUT),XML)
CFLAGS += -DOUTPUT=OUTPUT_XML

149
sys/include/net/ng_fib.h Normal file
View File

@ -0,0 +1,149 @@
/*
* Copyright (C) 2014 Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
*
* 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_fib Forwarding Information Base (FIB)
* @ingroup net
* @brief FIB implementation
*
* @{
*
* @file
* @brief Types and functions for FIB
* @author Martin Landsmann
*/
#ifndef FIB_H_
#define FIB_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reactive Routing Protocol (RRP) message content to request/reply route discovery
*/
typedef struct rrp_address_msg_t {
uint8_t *address; /**< The pointer to the address */
uint8_t address_size; /**< The address size */
uint32_t address_flags; /**< The flags for the given address */
} rrp_address_msg_t;
#define FIB_MSG_RRP_SIGNAL (0x99) /**< message type for RRP notifications */
/**
* @brief indicator of a lifetime that does not expire (2^32 - 1)
*/
#define FIB_LIFETIME_NO_EXPIRE (0xFFFFFFFF)
/**
* @brief initializes all FIB entries with 0
*/
void fib_init(void);
/**
* @brief de-initializes the FIB entries
*/
void fib_deinit(void);
/**
* @brief Registration of reactive routing protocol handler function
*/
void fib_register_rrp(void);
/**
* @brief Adds a new entry in the corresponding FIB table for global destination and next hop
*
* @param[in] iface_id the interface ID
* @param[in] dst the destination address
* @param[in] dst_size the destination address size
* @param[in] dst_flags the destination address flags
* @param[in] next_hop the next hop address to be updated
* @param[in] next_hop_size the next hop address size
* @param[in] next_hop_flags the next-hop address flags
* @param[in] lifetime the lifetime in ms to be updates
*
* @return 0 on success
* -ENOMEM if the entry cannot be created due to unsufficient RAM
*/
int fib_add_entry(kernel_pid_t iface_id, uint8_t *dst, size_t dst_size, uint32_t dst_flags,
uint8_t *next_hop, size_t next_hop_size, uint32_t next_hop_flags,
uint32_t lifetime);
/**
* @brief Updates an entry in the FIB table with next hop and lifetime
*
* @param[in] dst the destination address
* @param[in] dst_size the destination address size
* @param[in] next_hop the next hop address to be updated
* @param[in] next_hop_size the next hop address size
* @param[in] next_hop_flags the next-hop address flags
* @param[in] lifetime the lifetime in ms to be updates
*
* @return 0 on success
* -ENOMEM if the entry cannot be updated due to unsufficient RAM
*/
int fib_update_entry(uint8_t *dst, size_t dst_size,
uint8_t *next_hop, size_t next_hop_size, uint32_t next_hop_flags,
uint32_t lifetime);
/**
* @brief removes an entry from the corresponding FIB table
*
* @param[in] dst the destination address
* @param[in] dst_size the destination address size
*/
void fib_remove_entry(uint8_t *dst, size_t dst_size);
/**
* @brief provides a next hop for a given destination
*
* @param[in, out] iface_id pointer to store the interface ID for the next hop
* @param[out] next_hop pointer where the next hop address should be stored
* @param[in, out] next_hop_size the next hop address size. The value is
* overwritten with the actual next hop size
* @param[out] next_hop_flags the next-hop address flags, e.g. compression type
* @param[in] dst the destination address
* @param[in] dst_size the destination address size
* @param[in] dst_flags the destination address flags
*
* @return 0 on success
* -EHOSTUNREACH if no next hop is available in any FIB table
* all RRPs are notified before the return
* -ENOBUFS if the size for the next hop address is insufficient low
*/
int fib_get_next_hop(kernel_pid_t *iface_id,
uint8_t *next_hop, size_t *next_hop_size, uint32_t* next_hop_flags,
uint8_t *dst, size_t dst_size, uint32_t dst_flags);
/**
* @brief returns the actual number of used FIB entries
*/
int fib_get_num_used_entries(void);
/**
* @brief Prints the kernel_pid_t for all registered RRPs
*/
void fib_print_notify_rrp(void);
/**
* @brief Prints the FIB content (does not print the entries)
*/
void fib_print_fib_table(void);
/**
* @brief Prints the FIB content
*/
void fib_print_routes(void);
#ifdef __cplusplus
}
#endif
#endif /* FIB_H_ */
/** @} */

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2014 Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
*
* 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.
*/
/**
* @brief forwarding table structs
* @ingroup net_fib
*
* @{
*
* @file
* @brief Types and functions for operating fib tables
* @author Martin Landsmann
*/
#ifndef FIB_TABLE_H_
#define FIB_TABLE_H_
#include <stdint.h>
#include "vtimer.h"
#include "ng_universal_address.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Container descriptor for a FIB entry
*/
typedef struct fib_entry_t {
/** interface ID */
kernel_pid_t iface_id;
/** Lifetime of this entry */
timex_t lifetime;
/** Unique identifier for the type of the global address */
uint32_t global_flags;
/** Pointer to the shared generic address */
struct universal_address_container_t *global;
/** Unique identifier for the type of the next hop address */
uint32_t next_hop_flags;
/** Pointer to the shared generic address */
struct universal_address_container_t *next_hop;
} fib_entry_t;
#ifdef __cplusplus
}
#endif
#endif /* FIB_TABLE_H_ */
/** @} */

View File

@ -0,0 +1,121 @@
/*
* Copyright (C) 2014 Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
*
* 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_universal_address Universal Address Container
* @ingroup net
* @brief universal address container
*
* @{
*
* @file
* @brief Types and functions for operating universal addresses
* @author Martin Landsmann
*/
#ifndef UNIVERSAL_ADDRESS_H_
#define UNIVERSAL_ADDRESS_H_
#ifdef __cplusplus
extern "C" {
#endif
#define UNIVERSAL_ADDRESS_SIZE (16) /**< size of the used addresses in bytes */
/**
* @brief The container descriptor used to identify a universal address entry
*/
typedef struct universal_address_container_t {
uint8_t use_count; /**< The number of entries link here */
uint8_t address_size; /**< Size in bytes of the used genereic address */
uint8_t address[UNIVERSAL_ADDRESS_SIZE]; /**< the genereic address data */
} universal_address_container_t;
/**
* @brief initializes the datastructure for the entries
*/
void universal_address_init(void);
/**
* @brief resets the usecoumt for all entries
*/
void universal_address_reset(void);
/**
* @brief Adds a given address to the universal address entries
* if the entry already exists, the use_count will be increased.
*
* @param[in] addr pointer to the address
* @param[in] addr_size the number of bytes required for the address entry
*
* @return pointer to the universal_address_container_t containing the address on success
* NULL if the address could not be inserted
*/
universal_address_container_t *universal_address_add(uint8_t *addr, size_t addr_size);
/**
* @brief Adds a given container from the universal address entries
* if the entry exists, the use_count will be decreased.
*
* @param[in] entry pointer to the universal_address_container_t to be removed
*/
void universal_address_rem(universal_address_container_t *entry);
/**
* @brief copies the address from the given container to the provided pointer
*
* @param[in] entry pointer to the universal_address_container_t
* @param[out] addr pointer to store the address entry
* @param[in, out] addr_size pointer providing the size of available memory on addr
* this value is overwritten with the actual size required
*
* @return addr if the address is copied to the addr destination
* NULL if the size is unsufficient for copy
*/
uint8_t* universal_address_get_address(universal_address_container_t *entry,
uint8_t *addr, size_t *addr_size);
/**
* @brief determines if the entry equals the provided address
*
* @param[in] entry pointer to the universal_address_container_t for compare
* @param[in] addr pointer to the address for compare
* @param[in, out] addr_size the number of bytes used for the address entry
* on sucessfull return this value is overwritten
* with the number of matching bytes till the
* first of trailing `0`s indicating a prefix
*
* @return 0 if the entries are equal or comperable
* -ENOENT if the given adresses do not match
*/
int universal_address_compare(universal_address_container_t *entry,
uint8_t *addr, size_t *addr_size);
/**
* @brief Prints the content of the given entry
*
* @param[in] entry pointer to the universal_address_container_t to be printed
*/
void universal_address_print_entry(universal_address_container_t *entry);
/**
* @brief returns the number of used entries
*/
int universal_address_get_num_used_entries(void);
/**
* @brief Prints the content of the genereic address table up to the used element
*/
void universal_address_print_table(void);
#ifdef __cplusplus
}
#endif
#endif /* UNIVERSAL_ADDRESS_H_ */
/** @} */

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,584 @@
/**
* FIB implementation
*
* Copyright (C) 2014 Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
*
* 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.
*
* @ingroup fib
* @{
* @file fib.c
* @brief Functions to manage FIB entries
* @author Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
* @}
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "thread.h"
#include "mutex.h"
#include "msg.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "ng_fib.h"
#include "ng_fib/ng_fib_table.h"
/**
* @brief access mutex to control exclusive operations on calls
*/
static mutex_t mtx_access = MUTEX_INIT;
/**
* @brief maximum number of handled reactice routing protocols (RRP)
* used to notify the saved kernel_pid_t
*/
#define FIB_MAX_RRP (5)
/**
* @brief registered RRPs for notification un unreachable destinations
*/
static size_t notify_rrp_pos = 0;
/**
* @brief the kernel_pid_t for notifying the RRPs
*/
static kernel_pid_t notify_rrp[FIB_MAX_RRP];
/**
* @brief maximum number of FIB tables entries handled
*/
#define FIB_MAX_FIB_TABLE_ENTRIES (20)
/**
* @brief array of the FIB tables
*/
static fib_entry_t fib_table[FIB_MAX_FIB_TABLE_ENTRIES];
/**
* @brief convert given ms to a timepoint from now on in the future
* @param[in] ms the miliseconds to be converted
* @param[out] timex the converted timepoint
*/
static void fib_ms_to_timex(uint32_t ms, timex_t *timex)
{
vtimer_now(timex);
timex->seconds += ms / 1000;
timex->microseconds += (ms - timex->seconds * 1000) * 1000;
}
/**
* @brief returns pointer to the entry for the given destination address
*
* @param[in] dst the destination address
* @param[in] dst_size the destination address size
* @param[out] entry_arr the array to scribe the found match
* @param[in, out] entry_arr_size the number of entries provided by entry_arr (should be always 1)
* this value is overwritten with the actual found number
*
* @return 0 if we found a next-hop prefix
* 1 if we found the exact address next-hop
* -EHOSTUNREACH if no fitting next-hop is available
*/
static int fib_find_entry(uint8_t *dst, size_t dst_size,
fib_entry_t **entry_arr, size_t *entry_arr_size)
{
timex_t now;
vtimer_now(&now);
size_t count = 0;
size_t prefix_size = 0;
size_t match_size = dst_size;
int ret = -EHOSTUNREACH;
for (size_t i = 0; i < FIB_MAX_FIB_TABLE_ENTRIES; ++i) {
/* autoinvalidate if the entry lifetime is not set to not expire */
if ((fib_table[i].lifetime.seconds != FIB_LIFETIME_NO_EXPIRE)
|| (fib_table[i].lifetime.microseconds != FIB_LIFETIME_NO_EXPIRE)) {
/* check if the lifetime expired */
if (timex_cmp(now, fib_table[i].lifetime) > -1) {
/* remove this entry if its lifetime expired */
fib_table[i].lifetime.seconds = 0;
fib_table[i].lifetime.microseconds = 0;
if (fib_table[i].global != NULL) {
universal_address_rem(fib_table[i].global);
fib_table[i].global = NULL;
}
if (fib_table[i].next_hop != NULL) {
universal_address_rem(fib_table[i].next_hop);
fib_table[i].next_hop = NULL;
}
}
}
if ((prefix_size < dst_size) &&
(fib_table[i].global != NULL) &&
(universal_address_compare(fib_table[i].global, dst, &match_size) == 0)) {
/* If we found an exact match */
if (match_size == dst_size) {
entry_arr[0] = &(fib_table[i]);
*entry_arr_size = 1;
/* we will not find a better one so we return */
return 1;
}
else {
/* we try to find the most fitting prefix */
if (match_size > prefix_size) {
entry_arr[0] = &(fib_table[i]);
/* we could find a better one so we move on */
ret = 0;
}
}
prefix_size = match_size;
match_size = dst_size;
count = 1;
}
}
*entry_arr_size = count;
return ret;
}
/**
* @brief updates the next hop the lifetime and the interface id for a given entry
*
* @param[in] entry the entry to be updated
* @param[in] next_hop the next hop address to be updated
* @param[in] next_hop_size the next hop address size
* @param[in] next_hop_flags the next-hop address flags
* @param[in] lifetime the lifetime in ms
*
* @return 0 if the entry has been updated
* -ENOMEM if the entry cannot be updated due to unsufficient RAM
*/
static int fib_upd_entry(fib_entry_t *entry,
uint8_t *next_hop, size_t next_hop_size, uint32_t next_hop_flags,
uint32_t lifetime)
{
universal_address_container_t *container = universal_address_add(next_hop, next_hop_size);
if (container == NULL) {
return -ENOMEM;
}
universal_address_rem(entry->next_hop);
entry->next_hop = container;
entry->next_hop_flags = next_hop_flags;
if (lifetime < FIB_LIFETIME_NO_EXPIRE) {
fib_ms_to_timex(lifetime, &entry->lifetime);
}
else {
entry->lifetime.seconds = FIB_LIFETIME_NO_EXPIRE;
entry->lifetime.microseconds = FIB_LIFETIME_NO_EXPIRE;
}
return 0;
}
/**
* @brief creates a new FIB entry with the provided parameters
*
* @param[in] iface_id the interface ID
* @param[in] dst the destination address
* @param[in] dst_size the destination address size
* @param[in] dst_flags the destination address flags
* @param[in] next_hop the next hop address
* @param[in] next_hop_size the next hop address size
* @param[in] next_hop_flags the next-hop address flags
* @param[in] lifetime the lifetime in ms
*
* @return 0 on success
* -ENOMEM if no new entry can be created
*/
static int fib_create_entry(kernel_pid_t iface_id,
uint8_t *dst, size_t dst_size, uint32_t dst_flags,
uint8_t *next_hop, size_t next_hop_size, uint32_t next_hop_flags,
uint32_t lifetime)
{
for (size_t i = 0; i < FIB_MAX_FIB_TABLE_ENTRIES; ++i) {
if (fib_table[i].lifetime.seconds == 0 && fib_table[i].lifetime.microseconds == 0) {
fib_table[i].global = universal_address_add(dst, dst_size);
if (fib_table[i].global != NULL) {
fib_table[i].global_flags = dst_flags;
fib_table[i].next_hop = universal_address_add(next_hop, next_hop_size);
fib_table[i].next_hop_flags = next_hop_flags;
}
if (fib_table[i].next_hop != NULL) {
/* everything worked fine */
fib_table[i].iface_id = iface_id;
if (lifetime < FIB_LIFETIME_NO_EXPIRE) {
fib_ms_to_timex(lifetime, &fib_table[i].lifetime);
}
else {
fib_table[i].lifetime.seconds = FIB_LIFETIME_NO_EXPIRE;
fib_table[i].lifetime.microseconds = FIB_LIFETIME_NO_EXPIRE;
}
return 0;
}
}
}
return -ENOMEM;
}
/**
* @brief removes the given entry
*
* @param[in] entry the entry to be removed
*
* @return 0 on success
*/
static int fib_remove(fib_entry_t *entry)
{
if (entry->global != NULL) {
universal_address_rem(entry->global);
}
if (entry->next_hop) {
universal_address_rem(entry->next_hop);
}
entry->global = NULL;
entry->global_flags = 0;
entry->next_hop = NULL;
entry->next_hop_flags = 0;
entry->iface_id = KERNEL_PID_UNDEF;
entry->lifetime.seconds = 0;
entry->lifetime.microseconds = 0;
return 0;
}
/**
* @brief signalls (sends a message to) all registered RRPs
* to start a route discovery for the provided destination.
* The receiver MUST copy the content, i.e. the address before reply.
*
* @param[in] dst the destination address
* @param[in] dst_size the destination address size
*
* @return 0 on a new available entry,
* -ENOENT if no suiting entry is provided.
*/
static int fib_signal_rrp(uint8_t *dst, size_t dst_size, uint32_t dst_flags)
{
msg_t msg, reply;
rrp_address_msg_t content;
content.address = dst;
content.address_size = dst_size;
content.address_flags = dst_flags;
int ret = -ENOENT;
msg.type = FIB_MSG_RRP_SIGNAL;
msg.content.ptr = (void *)&content;
for (size_t i = 0; i < FIB_MAX_RRP; ++i) {
if (notify_rrp[i] != KERNEL_PID_UNDEF) {
DEBUG("[fib_signal_rrp] send msg@: %p to pid[%d]: %d\n", \
msg.content.ptr, (int)i, (int)notify_rrp[i]);
/* the receiver, i.e. the RRP, MUST copy the content value.
* using the provided pointer after replying this message
* will lead to errors
*/
msg_send_receive(&msg, &reply, notify_rrp[i]);
DEBUG("[fib_signal_rrp] got reply.");
}
}
return ret;
}
int fib_add_entry(kernel_pid_t iface_id, uint8_t *dst, size_t dst_size, uint32_t dst_flags,
uint8_t *next_hop, size_t next_hop_size, uint32_t next_hop_flags,
uint32_t lifetime)
{
mutex_lock(&mtx_access);
DEBUG("[fib_add_entry]");
size_t count = 1;
fib_entry_t *entry[count];
int ret = fib_find_entry(dst, dst_size, &(entry[0]), &count);
if (ret == 1) {
/* we must take the according entry and update the values */
ret = fib_upd_entry(entry[0], next_hop, next_hop_size, next_hop_flags, lifetime);
}
else {
ret = fib_create_entry(iface_id, dst, dst_size, dst_flags,
next_hop, next_hop_size, next_hop_flags, lifetime);
}
mutex_unlock(&mtx_access);
return ret;
}
int fib_update_entry(uint8_t *dst, size_t dst_size,
uint8_t *next_hop, size_t next_hop_size, uint32_t next_hop_flags,
uint32_t lifetime)
{
mutex_lock(&mtx_access);
DEBUG("[fib_update_entry]");
size_t count = 1;
fib_entry_t *entry[count];
int ret = -ENOMEM;
if (fib_find_entry(dst, dst_size, &(entry[0]), &count) == 1) {
DEBUG("[fib_update_entry] found entry: %p\n", (void *)(entry[0]));
/* we must take the according entry and update the values */
ret = fib_upd_entry(entry[0], next_hop, next_hop_size, next_hop_flags, lifetime);
}
else {
/* we have ambigious entries, i.e. count > 1
* this should never happen
*/
DEBUG("[fib_update_entry] ambigious entries detected!!!");
}
mutex_unlock(&mtx_access);
return ret;
}
void fib_remove_entry(uint8_t *dst, size_t dst_size)
{
mutex_lock(&mtx_access);
DEBUG("[fib_remove_entry]");
size_t count = 1;
fib_entry_t *entry[count];
int ret = fib_find_entry(dst, dst_size, &(entry[0]), &count);
if (ret == 1) {
/* we must take the according entry and update the values */
fib_remove(entry[0]);
}
else {
/* we have ambigious entries, i.e. count > 1
* this should never happen
*/
DEBUG("[fib_update_entry] ambigious entries detected!!!");
}
mutex_unlock(&mtx_access);
}
int fib_get_next_hop(kernel_pid_t *iface_id,
uint8_t *next_hop, size_t *next_hop_size, uint32_t *next_hop_flags,
uint8_t *dst, size_t dst_size, uint32_t dst_flags)
{
mutex_lock(&mtx_access);
DEBUG("[fib_get_next_hop]");
size_t count = 1;
fib_entry_t *entry[count];
int ret = fib_find_entry(dst, dst_size, &(entry[0]), &count);
if (!(ret == 0 || ret == 1)) {
/* notify all RRPs for route discovery if available */
if (fib_signal_rrp(dst, dst_size, dst_flags) == 0) {
count = 1;
/* now lets see if the RRPs have found a valid next-hop */
ret = fib_find_entry(dst, dst_size, &(entry[0]), &count);
}
}
if (ret == 0 || ret == 1) {
uint8_t *address_ret = universal_address_get_address(entry[0]->next_hop,
next_hop, next_hop_size);
if (address_ret == NULL) {
mutex_unlock(&mtx_access);
return -ENOBUFS;
}
}
else {
mutex_unlock(&mtx_access);
return -EHOSTUNREACH;
}
*iface_id = entry[0]->iface_id;
*next_hop_flags = entry[0]->next_hop_flags;
mutex_unlock(&mtx_access);
return 0;
}
void fib_init(void)
{
DEBUG("[fib_init] hello. Initializing some stuff.");
mutex_lock(&mtx_access);
for (size_t i = 0; i < FIB_MAX_RRP; ++i) {
notify_rrp[i] = KERNEL_PID_UNDEF;
}
for (size_t i = 0; i < FIB_MAX_FIB_TABLE_ENTRIES; ++i) {
fib_table[i].iface_id = 0;
fib_table[i].lifetime.seconds = 0;
fib_table[i].lifetime.microseconds = 0;
fib_table[i].global_flags = 0;
fib_table[i].global = NULL;
fib_table[i].next_hop_flags = 0;
fib_table[i].next_hop = NULL;
}
universal_address_init();
mutex_unlock(&mtx_access);
}
void fib_deinit(void)
{
DEBUG("[fib_deinit] hello. De-Initializing stuff.");
mutex_lock(&mtx_access);
for (size_t i = 0; i < FIB_MAX_RRP; ++i) {
notify_rrp[i] = KERNEL_PID_UNDEF;
}
notify_rrp_pos = 0;
for (size_t i = 0; i < FIB_MAX_FIB_TABLE_ENTRIES; ++i) {
fib_table[i].iface_id = 0;
fib_table[i].lifetime.seconds = 0;
fib_table[i].lifetime.microseconds = 0;
fib_table[i].global_flags = 0;
fib_table[i].global = NULL;
fib_table[i].next_hop_flags = 0;
fib_table[i].next_hop = NULL;
}
universal_address_reset();
mutex_unlock(&mtx_access);
}
void fib_register_rrp(void)
{
mutex_lock(&mtx_access);
if (notify_rrp_pos < FIB_MAX_RRP) {
notify_rrp[notify_rrp_pos] = sched_active_pid;
notify_rrp_pos++;
}
mutex_unlock(&mtx_access);
}
int fib_get_num_used_entries(void)
{
mutex_lock(&mtx_access);
size_t used_entries = 0;
for (size_t i = 0; i < FIB_MAX_FIB_TABLE_ENTRIES; ++i) {
used_entries += (size_t)(fib_table[i].global != NULL);
}
mutex_unlock(&mtx_access);
return used_entries;
}
/* print functions */
void fib_print_notify_rrp(void)
{
mutex_lock(&mtx_access);
for (size_t i = 0; i < FIB_MAX_RRP; ++i) {
printf("[fib_print_notify_rrp] pid[%d]: %d\n", (int)i, (int)notify_rrp[i]);
}
mutex_unlock(&mtx_access);
}
void fib_print_fib_table(void)
{
mutex_lock(&mtx_access);
for (size_t i = 0; i < FIB_MAX_FIB_TABLE_ENTRIES; ++i) {
printf("[fib_print_fib_table] %d) iface_id: %d, global: %p, next hop: %p, lifetime: %d.%d\n", \
(int)i, \
(int)fib_table[i].iface_id, \
(void *)fib_table[i].global, \
(void *)fib_table[i].next_hop, \
(int)fib_table[i].lifetime.seconds, \
(int)fib_table[i].lifetime.microseconds);
}
mutex_unlock(&mtx_access);
}
static void fib_print_adress(universal_address_container_t *entry)
{
uint8_t address[UNIVERSAL_ADDRESS_SIZE];
size_t addr_size = UNIVERSAL_ADDRESS_SIZE;
uint8_t *ret = universal_address_get_address(entry, address, &addr_size);
if (ret == address) {
for (size_t i = 0; i < UNIVERSAL_ADDRESS_SIZE; ++i) {
if (i <= addr_size) {
printf("%02x", address[i]);
}
else {
printf(" ");
}
}
}
}
void fib_print_routes(void)
{
mutex_lock(&mtx_access);
printf("%-32s %-6s %-32s %-6s %-16s Interface\n"
, "Destination", "Flags", "Next Hop", "Flags", "Expires");
timex_t now;
vtimer_now(&now);
for (size_t i = 0; i < FIB_MAX_FIB_TABLE_ENTRIES; ++i) {
if (fib_table[i].lifetime.seconds != 0 || fib_table[i].lifetime.microseconds != 0) {
fib_print_adress(fib_table[i].global);
printf(" 0x%04x ", fib_table[i].global_flags);
fib_print_adress(fib_table[i].next_hop);
printf(" 0x%04x ", fib_table[i].next_hop_flags);
if ((fib_table[i].lifetime.seconds != FIB_LIFETIME_NO_EXPIRE)
|| (fib_table[i].lifetime.microseconds != FIB_LIFETIME_NO_EXPIRE)) {
timex_t tm = timex_sub(fib_table[i].lifetime, now);
/* we must interpret the values as signed */
if ((int32_t)tm.seconds < 0
|| (tm.seconds == 0 && (int32_t)tm.microseconds < 0)) {
printf("%-16s ", "EXPIRED");
}
else {
printf("%"PRIu32".%05"PRIu32, tm.seconds, tm.microseconds);
}
}
else {
printf("%-16s ", "NEVER");
}
printf("%d\n", (int)fib_table[i].iface_id);
}
}
mutex_unlock(&mtx_access);
}

View File

@ -0,0 +1,261 @@
/**
* universal address container implementation
*
* Copyright (C) 2014 Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
*
* 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.
*
* @ingroup fib
* @{
* @file universal_address.c
* @brief Functions to manage universal address container
* @author Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
* @}
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "mutex.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "ng_fib/ng_universal_address.h"
/**
* @brief Maximum number of entries handled
*/
#define UNIVERSAL_ADDRESS_MAX_ENTRIES (40)
/**
* @brief counter indicating the number of entries allocated
*/
static size_t universal_address_table_filled = 0;
/**
* @brief The array of universal_address containers
*/
static universal_address_container_t universal_address_table[UNIVERSAL_ADDRESS_MAX_ENTRIES];
/**
* @brief access mutex to control exclusive operations on calls
*/
static mutex_t mtx_access = MUTEX_INIT;
/**
* @brief finds the universal address container for the given address
*
* @param[in] addr pointer to the address
* @param[in] addr_size the number of bytes required for the address entry
*
* @return pointer to the universal_address_container_t containing the address on success
* NULL if the address could not be inserted
*/
static universal_address_container_t *universal_address_find_entry(uint8_t *addr, size_t addr_size)
{
for (size_t i = 0; i < UNIVERSAL_ADDRESS_MAX_ENTRIES; ++i) {
if ((universal_address_table[i].address_size == addr_size) && (universal_address_table[i].address != NULL)) {
if (memcmp((universal_address_table[i].address), addr, addr_size) == 0) {
return &(universal_address_table[i]);
}
}
}
return NULL;
}
/**
* @brief finds the next empty or unused universal address containers
*
* @return pointer to the next free/unused universal_address_container_t
* or NULL if no memory is left in universal_address_table
*/
static universal_address_container_t *universal_address_get_next_unused_entry(void)
{
if (universal_address_table_filled < UNIVERSAL_ADDRESS_MAX_ENTRIES) {
for (size_t i = 0; i < UNIVERSAL_ADDRESS_MAX_ENTRIES; ++i) {
if ((universal_address_table[i].use_count == 0)) {
return &(universal_address_table[i]);
}
}
}
return NULL;
}
universal_address_container_t *universal_address_add(uint8_t *addr, size_t addr_size)
{
mutex_lock(&mtx_access);
universal_address_container_t *pEntry = universal_address_find_entry(addr, addr_size);
if (pEntry == NULL) {
/* look for a free entry */
pEntry = universal_address_get_next_unused_entry();
if (pEntry == NULL) {
mutex_unlock(&mtx_access);
/* no free room */
return NULL;
}
/* look if the former memory has distinct size */
if (pEntry->address_size != addr_size) {
/* clean the address */
memset(pEntry->address, 0, UNIVERSAL_ADDRESS_SIZE);
/* set the used bytes */
pEntry->address_size = addr_size;
pEntry->use_count = 0;
}
/* copy the address */
memcpy((pEntry->address), addr, addr_size);
}
pEntry->use_count++;
if (pEntry->use_count == 1) {
DEBUG("[universal_address_add] universal_address_table_filled: %d\n", \
(int)universal_address_table_filled);
universal_address_table_filled++;
}
mutex_unlock(&mtx_access);
return pEntry;
}
void universal_address_rem(universal_address_container_t *entry)
{
mutex_lock(&mtx_access);
DEBUG("[universal_address_rem] entry: %p\n", (void *)entry);
/* we do not delete anything on remove */
if (entry != NULL) {
if (entry->use_count != 0) {
entry->use_count--;
if (entry->use_count == 0) {
universal_address_table_filled--;
}
}
else {
DEBUG("[universal_address_rem] universal_address_table_filled: %d\n", \
(int)universal_address_table_filled);
}
}
mutex_unlock(&mtx_access);
}
uint8_t* universal_address_get_address(universal_address_container_t *entry,
uint8_t *addr, size_t *addr_size)
{
mutex_lock(&mtx_access);
if (*addr_size >= entry->address_size) {
memcpy(addr, entry->address, entry->address_size);
*addr_size = entry->address_size;
mutex_unlock(&mtx_access);
return addr;
}
*addr_size = entry->address_size;
mutex_unlock(&mtx_access);
return NULL;
}
int universal_address_compare(universal_address_container_t *entry,
uint8_t *addr, size_t *addr_size)
{
mutex_lock(&mtx_access);
int ret = -ENOENT;
/* If we have distinct sizes, the addresses are probably not comperable */
if (entry->address_size != *addr_size) {
mutex_unlock(&mtx_access);
return ret;
}
/* Get the index of the first trailing `0` (indicates a network prefix) */
int i = 0;
for( i = entry->address_size-1; i >= 0; --i) {
if( entry->address[i] != 0 ) {
break;
}
}
if( memcmp(entry->address, addr, i+1) == 0 ) {
ret = 0;
*addr_size = i+1;
}
mutex_unlock(&mtx_access);
return ret;
}
void universal_address_init(void)
{
mutex_lock(&mtx_access);
for (size_t i = 0; i < UNIVERSAL_ADDRESS_MAX_ENTRIES; ++i) {
universal_address_table[i].use_count = 0;
universal_address_table[i].address_size = 0;
memset(universal_address_table[i].address, 0, UNIVERSAL_ADDRESS_SIZE);
}
mutex_unlock(&mtx_access);
}
void universal_address_reset(void)
{
mutex_lock(&mtx_access);
for (size_t i = 0; i < UNIVERSAL_ADDRESS_MAX_ENTRIES; ++i) {
universal_address_table[i].use_count = 0;
}
universal_address_table_filled = 0;
mutex_unlock(&mtx_access);
}
void universal_address_print_entry(universal_address_container_t *entry)
{
mutex_lock(&mtx_access);
if (entry != NULL) {
printf("[universal_address_print_entry] entry@: %p, use_count: %d, \
address_size: %d, content: ", \
(void *)entry, (int)entry->use_count, (int)entry->address_size);
for (size_t i = 0; i < entry->address_size; ++i) {
/* printf("%02x ", (char)entry->address[i]); */
printf("%c", (char)entry->address[i]);
}
puts("");
}
mutex_unlock(&mtx_access);
}
int universal_address_get_num_used_entries(void)
{
mutex_lock(&mtx_access);
size_t ret = universal_address_table_filled;
mutex_unlock(&mtx_access);
return ret;
}
void universal_address_print_table(void)
{
printf("[universal_address_print_table] universal_address_table_filled: %d\n", \
(int)universal_address_table_filled);
for (size_t i = 0; i < UNIVERSAL_ADDRESS_MAX_ENTRIES; ++i) {
universal_address_print_entry((&universal_address_table[i]));
}
}

View File

@ -58,6 +58,9 @@ endif
ifneq (,$(filter ng_netif,$(USEMODULE)))
SRC += sc_netif.c
endif
ifneq (,$(filter fib,$(USEMODULE)))
SRC += sc_fib.c
endif
# TODO
# Conditional building not possible at the moment due to

210
sys/shell/commands/sc_fib.c Normal file
View File

@ -0,0 +1,210 @@
/*
* Copyright (C) 2015 Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
*
* 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.
*/
/**
* @ingroup sys_shell_commands
* @{
*
* @file
* @brief Provides shell commands to manage and show FIB Entries
*
* @author 2015 Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "thread.h"
#include "inet_pton.h"
#include "ng_fib.h"
#define INFO1_TXT "fibroute add <destination> via <next hop> dev <device>"
#define INFO2_TXT " [lifetime <lifetime>]"
#define INFO3_TXT " <destination> - the destination address\n" \
" <next hop> - the address of the next-hop towards the <destination>\n" \
" <device> - the device id of the Interface to use\n"
#define INFO4_TXT " <lifetime> - optional lifetime in ms when the entry automatically invalidates\n"
#define INFO5_TXT "fibroute del <destination>\n" \
" <destination> - the destination address of the entry to be deleted\n"
static unsigned char tmp_ipv4_dst[INADDRSZ]; /**< buffer for ipv4 address conversion */
static unsigned char tmp_ipv4_nxt[INADDRSZ]; /**< buffer for ipv4 address conversion */
static unsigned char tmp_ipv6_dst[IN6ADDRSZ]; /**< buffer for ipv6 address conversion */
static unsigned char tmp_ipv6_nxt[IN6ADDRSZ]; /**< buffer for ipv6 address conversion */
static void _fib_usage(int info)
{
switch (info) {
case 1: {
puts("\nbrief: adds a new entry to the FIB.\nusage: "
INFO1_TXT "\n" INFO3_TXT);
break;
}
case 2: {
puts("\nbrief: adds a new entry to the FIB.\nusage: "
INFO1_TXT INFO2_TXT "\n" INFO3_TXT INFO4_TXT);
break;
}
case 3: {
puts("\nbrief: deletes an entry from the FIB.\nusage: "
INFO5_TXT);
break;
}
default:
break;
};
}
void _fib_route_handler(int argc, char **argv)
{
/* e.g. fibroute right now dont care about the adress/protocol family */
if (argc == 1) {
fib_print_routes();
return;
}
/* e.g. firoute [add|del] */
if (argc == 2) {
if ((strcmp("add", argv[1]) == 0)) {
_fib_usage(2);
}
else if ((strcmp("del", argv[1]) == 0)) {
_fib_usage(3);
}
else {
puts("\nunrecognized parameter1.\nPlease enter fibroute [add|del] for more information.");
}
return;
}
if (argc > 2 && !((strcmp("add", argv[1]) == 0) || (strcmp("del", argv[1]) == 0))) {
puts("\nunrecognized parameter2.\nPlease enter fibroute [add|del] for more information.");
return;
}
/* e.g. fibroute del <destination> */
if (argc == 3) {
if (inet_pton(AF_INET6, argv[2], tmp_ipv6_dst)) {
fib_remove_entry(tmp_ipv6_dst, IN6ADDRSZ);
}
else if (inet_pton(AF_INET, argv[2], tmp_ipv4_dst)) {
fib_remove_entry(tmp_ipv4_dst, INADDRSZ);
}
else {
fib_remove_entry((uint8_t *)argv[2], (strlen(argv[2])));
}
return;
}
/* e.g. fibroute add <destination> via <next hop> dev <device> */
if (argc == 7) {
if ((strcmp("add", argv[1]) == 0) && (strcmp("via", argv[3]) == 0)
&& (strcmp("dev", argv[5]) == 0)) {
unsigned char *dst = (unsigned char *)argv[2];
size_t dst_size = (strlen(argv[2]));
uint32_t dst_flags = 0xffff;
unsigned char *nxt = (unsigned char *)argv[4];
size_t nxt_size = (strlen(argv[4]));
uint32_t nxt_flags = 0xffff;
/* determine destination address */
if (inet_pton(AF_INET6, argv[2], tmp_ipv6_dst)) {
dst = tmp_ipv6_dst;
dst_size = IN6ADDRSZ;
dst_flags = AF_INET6;
}
else if (inet_pton(AF_INET, argv[2], tmp_ipv4_dst)) {
dst = tmp_ipv4_dst;
dst_size = INADDRSZ;
dst_flags = AF_INET;
}
/* determine next-hop address */
if (inet_pton(AF_INET6, argv[4], tmp_ipv6_nxt)) {
nxt = tmp_ipv6_nxt;
nxt_size = IN6ADDRSZ;
nxt_flags = AF_INET6;
}
else if (inet_pton(AF_INET, argv[4], tmp_ipv4_nxt)) {
nxt = tmp_ipv4_nxt;
nxt_size = INADDRSZ;
nxt_flags = AF_INET;
}
fib_add_entry((kernel_pid_t) atoi(argv[6]),
dst, dst_size, dst_flags,
nxt, nxt_size, nxt_flags,
FIB_LIFETIME_NO_EXPIRE);
}
else {
_fib_usage(1);
}
return;
}
/* e.g. fibroute add <destination> via <next hop> dev <device> lifetime <lifetime> */
if (argc == 9) {
if ((strcmp("add", argv[1]) == 0) && (strcmp("via", argv[3]) == 0)
&& (strcmp("dev", argv[5]) == 0)
&& (strcmp("lifetime", argv[7]) == 0)) {
unsigned char *dst = (unsigned char *)argv[2];
size_t dst_size = (strlen(argv[2]));
uint32_t dst_flags = 0xffff;
unsigned char *nxt = (unsigned char *)argv[4];
size_t nxt_size = (strlen(argv[4]));
uint32_t nxt_flags = 0xffff;
/* determine destination address */
if (inet_pton(AF_INET6, argv[2], tmp_ipv6_dst)) {
dst = tmp_ipv6_dst;
dst_size = IN6ADDRSZ;
dst_flags = AF_INET6;
}
else if (inet_pton(AF_INET, argv[2], tmp_ipv4_dst)) {
dst = tmp_ipv4_dst;
dst_size = INADDRSZ;
dst_flags = AF_INET;
}
/* determine next-hop address */
if (inet_pton(AF_INET6, argv[4], tmp_ipv6_nxt)) {
nxt = tmp_ipv6_nxt;
nxt_size = IN6ADDRSZ;
nxt_flags = AF_INET6;
}
else if (inet_pton(AF_INET, argv[4], tmp_ipv4_nxt)) {
nxt = tmp_ipv4_nxt;
nxt_size = INADDRSZ;
nxt_flags = AF_INET;
}
fib_add_entry((kernel_pid_t) atoi(argv[6]),
dst, dst_size, dst_flags,
nxt, nxt_size, nxt_flags,
(uint32_t)atoi(argv[8]));
}
else {
_fib_usage(2);
}
return;
}
puts("\nunrecognized parameters.\nPlease enter fibroute [add|del] for more information.");
}

View File

@ -159,6 +159,10 @@ extern int _netif_send(int argc, char **argv);
#endif
#endif
#ifdef MODULE_FIB
extern void _fib_route_handler( int argc, char **argv );
#endif
const shell_command_t _shell_command_list[] = {
{"reboot", "Reboot the node", _reboot_handler},
#ifdef MODULE_CONFIG
@ -259,6 +263,13 @@ const shell_command_t _shell_command_list[] = {
#ifndef MODULE_TRANSCEIVER
{"txtsnd", "send raw data", _netif_send },
#endif
#endif
#ifdef MODULE_FIB
{
"fibroute",
"Manipulate the FIB (info: 'fibroute [add|del]')",
_fib_route_handler
},
#endif
{NULL, NULL, NULL}
};

View File

@ -0,0 +1,3 @@
MODULE = tests-fib
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1 @@
USEMODULE += fib

View File

@ -0,0 +1,560 @@
/*
* Copyright (C) 2015 Martin Landsmann
*
* 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.
*/
#define TEST_FIB_SHOW_OUTPUT (0) /**< set */
#include <stdio.h> /**< required for snprintf() */
#include <string.h>
#include <errno.h>
#include "embUnit.h"
#include "tests-fib.h"
#include "thread.h"
#include "ng_fib.h"
#include "ng_fib/ng_universal_address.h"
/*
* @brief helper to fill FIB with unique entries
*/
static void _fill_FIB_unique(size_t entries)
{
size_t add_buf_size = 16;
char addr_dst[add_buf_size];
char addr_nxt[add_buf_size];
uint32_t addr_dst_flags = 0x77777777;
uint32_t addr_nxt_flags = 0x77777777;
for (size_t i = 0; i < entries; ++i) {
/* construct "addresses" for the FIB */
snprintf(addr_dst, add_buf_size, "Test address %02d", (int)i);
snprintf(addr_nxt, add_buf_size, "Test address %02d", entries + i);
/* the terminating \0 is unnecessary here */
fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, addr_dst_flags,
(uint8_t *)addr_nxt, add_buf_size - 1, addr_nxt_flags, 10000);
}
}
/*
* @brief helper to fill FIB with multiple used entries
* The modulus adjusts the number of reused addresses
*/
static void _fill_FIB_multiple(size_t entries, size_t modulus)
{
size_t add_buf_size = 16;
char addr_dst[add_buf_size];
char addr_nxt[add_buf_size];
uint32_t addr_dst_flags = 0x33333333;
uint32_t addr_nxt_flags = 0x33333333;
for (size_t i = 0; i < entries; ++i) {
/* construct "addresses" for the FIB */
snprintf(addr_dst, add_buf_size, "Test address %02d", (int)i);
snprintf(addr_nxt, add_buf_size, "Test address %02d", i % modulus);
fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, addr_dst_flags,
(uint8_t *)addr_nxt, add_buf_size - 1, addr_nxt_flags, 10000);
}
}
/*
* @brief filling the FIB with entries
* It is expected to have 20 FIB entries and 40 used universal address entries
*/
static void test_fib_01_fill_unique_entries(void)
{
_fill_FIB_unique(20);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(40, universal_address_get_num_used_entries());
fib_deinit();
}
/*
* @brief filling the FIB with reusable entries
* It is expected to have 20 FIB entries and 20 universal address entries
*/
static void test_fib_02_fill_multiple_entries(void)
{
size_t entries = 20;
_fill_FIB_multiple(entries, 11);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
fib_deinit();
}
/*
* @brief filling the FIB with entries and removing all entries
* It is expected to have 0 FIB entries and 0 universal address entries after remove
*/
static void test_fib_03_removing_all_entries(void)
{
size_t add_buf_size = 16;
char addr_dst[add_buf_size];
size_t entries = 20;
_fill_FIB_unique(entries);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(40, universal_address_get_num_used_entries());
for (size_t i = 0; i < entries; ++i) {
/* construct "addresses" to remove */
snprintf(addr_dst, add_buf_size, "Test address %02d", (int)i);
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
}
TEST_ASSERT_EQUAL_INT(0, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(0, universal_address_get_num_used_entries());
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
fib_deinit();
}
/*
* @brief filling the FIB with entries and removing the lower 1/2 entries (0..9)
* It is expected to have 10 FIB entries and 19 used universal address entries after remove
*/
static void test_fib_04_remove_lower_half(void)
{
size_t add_buf_size = 16;
char addr_dst[add_buf_size];
size_t entries = 20;
_fill_FIB_multiple(entries, 11);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
for (size_t i = 0; i < entries / 2; ++i) {
/* construct "addresses" to remove */
snprintf(addr_dst, add_buf_size, "Test address %02d", (int)i);
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
}
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
TEST_ASSERT_EQUAL_INT(10, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(19, universal_address_get_num_used_entries());
fib_deinit();
}
/*
* @brief filling the FIB with entries and removing the upper 1/2 entries (10..19)
* It is expected to have 10 FIB entries and 10 universal address entries after remove
*/
static void test_fib_05_remove_upper_half(void)
{
size_t add_buf_size = 16;
char addr_dst[add_buf_size];
size_t entries = 20;
_fill_FIB_multiple(entries, 11);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
for (size_t i = 0; i < entries / 2; ++i) {
/* construct "addresses" to remove */
snprintf(addr_dst, add_buf_size, "Test address %02d", ((entries / 2) + i));
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
}
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
TEST_ASSERT_EQUAL_INT(10, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(10, universal_address_get_num_used_entries());
fib_deinit();
}
/*
* @brief filling the FIB with entries and removing one entry
* It is expected to have 19 FIB entries and still 20 universal address entries
* after removing 02
* (the use count for 02 is reduced to 1 after remove)
*/
static void test_fib_06_remove_one_entry(void)
{
size_t add_buf_size = 16;
char addr_dst[] = "Test address 02";
size_t entries = 20;
_fill_FIB_multiple(entries, 11);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
TEST_ASSERT_EQUAL_INT(19, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
fib_deinit();
}
/*
* @brief filling the FIB with entries and removing one entry several times
* It is expected to have 19 FIB entries and 19 universal address entries
* after removing 13
*/
static void test_fib_07_remove_one_entry_multiple_times(void)
{
size_t add_buf_size = 16; /* includes space for terminating \0 */
char addr_dst[] = "Test address 13";
size_t entries = 20;
_fill_FIB_multiple(entries, 11);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
TEST_ASSERT_EQUAL_INT(19, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(19, universal_address_get_num_used_entries());
fib_deinit();
}
/*
* @brief filling the FIB with entries and removing an unknown entry
* It is expected to have 20 FIB entries and 20 universal address entries after removing
*/
static void test_fib_08_remove_unknown(void)
{
size_t add_buf_size = 16; /* includes space for terminating \0 */
char addr_dst[] = "Test address 99";
size_t entries = 20;
_fill_FIB_multiple(entries, 11);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
fib_remove_entry((uint8_t *)addr_dst, add_buf_size - 1);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
fib_deinit();
}
/*
* @brief filling the FIB with entries and update an entry
* It is expected to have FIB entry 13 with updated lifetime of 9999
* and entry 7 with updated iface ID of 7, lifetime of 7777 and next hop "Test address 77"
*/
static void test_fib_09_update_entry(void)
{
size_t add_buf_size = 16; /* includes space for terminating \0 */
char addr_dst13[] = "Test address 13";
char addr_dst07[] = "Test address 07";
char addr_nxt2[] = "Test address 99";
char addr_nxt77[] = "Test address 77";
size_t entries = 20;
_fill_FIB_multiple(entries, 11);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
fib_update_entry((uint8_t *)addr_dst13, add_buf_size - 1,
(uint8_t *)addr_nxt2, add_buf_size - 1, 0x99, 9999);
fib_update_entry((uint8_t *)addr_dst07, add_buf_size - 1,
(uint8_t *)addr_nxt77, add_buf_size - 1, 0x77, 7777);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
fib_deinit();
}
/*
* @brief filling the FIB with entries and adding an additional one (not fitting)
* It is expected to have 20 FIB entries and to receive FPC_ERROR on adding an additional one
*/
static void test_fib_10_add_exceed(void)
{
size_t add_buf_size = 16; /* includes space for terminating \0 */
char addr_dst[] = "Test address 98";
char addr_nxt[] = "Test address 99";
size_t entries = 20;
_fill_FIB_unique(entries);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(40, universal_address_get_num_used_entries());
int ret = fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x98,
(uint8_t *)addr_nxt, add_buf_size - 1, 0x99, 9999);
TEST_ASSERT_EQUAL_INT(-ENOMEM, ret);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(40, universal_address_get_num_used_entries());
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
fib_deinit();
}
/*
* @brief get next hop for known destination
* It is expected to get the next hop 02 and receive 0
*/
static void test_fib_11_get_next_hop_success(void)
{
size_t add_buf_size = 16; /* includes space for terminating \0 */
char addr_dst[] = "Test address 13";
char addr_expect[] = "Test address 02";
kernel_pid_t iface_id = KERNEL_PID_UNDEF;
uint32_t next_hop_flags = 0;
char addr_nxt[add_buf_size];
size_t entries = 20;
_fill_FIB_multiple(entries, 11);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
int ret = fib_get_next_hop(&iface_id,
(uint8_t *)addr_nxt, &add_buf_size, &next_hop_flags,
(uint8_t *)addr_dst, add_buf_size - 1, 0x13);
TEST_ASSERT_EQUAL_INT(0, ret);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
ret = strncmp(addr_expect, addr_nxt, add_buf_size);
TEST_ASSERT_EQUAL_INT(0, ret);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
fib_deinit();
}
/*
* @brief get next hop for unknown destination
* It is expected to get no next hop and receive -EHOSTUNREACH
*/
static void test_fib_12_get_next_hop_fail(void)
{
size_t add_buf_size = 16; /* includes space for terminating \0 */
char addr_dst[] = "Test address 99";
kernel_pid_t iface_id = KERNEL_PID_UNDEF;
uint32_t next_hop_flags = 0;
char addr_nxt[add_buf_size];
size_t entries = 20;
_fill_FIB_multiple(entries, 11);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
int ret = fib_get_next_hop(&iface_id,
(uint8_t *)addr_nxt, &add_buf_size, &next_hop_flags,
(uint8_t *)addr_dst, add_buf_size - 1, 0x99);
TEST_ASSERT_EQUAL_INT(-EHOSTUNREACH, ret);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
fib_deinit();
}
/*
* @brief get next hop for known destination but unsufficient size for the output
* It is expected to get no next hop and receive -ENOBUFS
*/
static void test_fib_13_get_next_hop_fail_on_buffer_size(void)
{
size_t add_buf_size = 16; /* includes space for terminating \0 */
char addr_dst[] = "Test address 13";
kernel_pid_t iface_id = KERNEL_PID_UNDEF;
uint32_t next_hop_flags = 0;
size_t add_buf_size_nxt = 12;
char addr_nxt[add_buf_size];
size_t entries = 20;
_fill_FIB_multiple(entries, 11);
TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries());
TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries());
int ret = fib_get_next_hop(&iface_id,
(uint8_t *)addr_nxt, &add_buf_size_nxt, &next_hop_flags,
(uint8_t *)addr_dst, add_buf_size - 1, 0x13);
TEST_ASSERT_EQUAL_INT(-ENOBUFS, ret);
TEST_ASSERT_EQUAL_INT(add_buf_size_nxt, add_buf_size - 1);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
fib_deinit();
}
/*
* @brief testing prefix and exact match
* It is expected receive 23 for addr123 as exact match and
* 12 for addr124
*/
static void test_fib_14_exact_and_prefix_match(void)
{
size_t add_buf_size = 16;
char addr_dst[add_buf_size];
char addr_nxt[add_buf_size];
kernel_pid_t iface_id = KERNEL_PID_UNDEF;
uint32_t next_hop_flags = 0;
char addr_lookup[add_buf_size];
memset(addr_dst, 0, add_buf_size);
memset(addr_nxt, 0, add_buf_size);
snprintf(addr_dst, add_buf_size, "Test addr12");
snprintf(addr_nxt, add_buf_size, "Test address %02d", 12);
fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x12,
(uint8_t *)addr_nxt, add_buf_size - 1, 0x12, 100000);
snprintf(addr_dst, add_buf_size, "Test addr123");
snprintf(addr_nxt, add_buf_size, "Test address %02d", 23);
fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x123,
(uint8_t *)addr_nxt, add_buf_size - 1, 0x23, 100000);
snprintf(addr_dst, add_buf_size, "Test addr1234");
snprintf(addr_nxt, add_buf_size, "Test address %02d", 34);
fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x1234,
(uint8_t *)addr_nxt, add_buf_size - 1, 0x34, 100000);
/* exact match */
snprintf(addr_lookup, add_buf_size, "Test addr123");
int ret = fib_get_next_hop(&iface_id,
(uint8_t *)addr_nxt, &add_buf_size, &next_hop_flags,
(uint8_t *)addr_lookup, add_buf_size - 1, 0x123);
TEST_ASSERT_EQUAL_INT(0, ret);
char addr_expect_01[] = "Test address 23";
ret = strncmp(addr_expect_01, addr_nxt, add_buf_size - 1);
TEST_ASSERT_EQUAL_INT(0, ret);
/* prefix match */
add_buf_size = 16;
memset(addr_nxt, 0, add_buf_size);
memset(addr_lookup, 0, add_buf_size);
/* cppcheck: addr_lookup is only passed but not required to be read,
* since we test prefix matching
*/
/* cppcheck-suppress redundantCopy */
snprintf(addr_lookup, add_buf_size, "Test addr124");
ret = fib_get_next_hop(&iface_id,
(uint8_t *)addr_nxt, &add_buf_size, &next_hop_flags,
(uint8_t *)addr_lookup, add_buf_size - 1, 0x124);
TEST_ASSERT_EQUAL_INT(0, ret);
add_buf_size = 16;
char addr_expect_02[] = "Test address 12";
ret = strncmp(addr_expect_02, addr_nxt, add_buf_size);
TEST_ASSERT_EQUAL_INT(0, ret);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
fib_deinit();
}
Test *tests_fib_tests(void)
{
fib_init();
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_fib_01_fill_unique_entries),
new_TestFixture(test_fib_02_fill_multiple_entries),
new_TestFixture(test_fib_03_removing_all_entries),
new_TestFixture(test_fib_04_remove_lower_half),
new_TestFixture(test_fib_05_remove_upper_half),
new_TestFixture(test_fib_06_remove_one_entry),
new_TestFixture(test_fib_07_remove_one_entry_multiple_times),
new_TestFixture(test_fib_08_remove_unknown),
new_TestFixture(test_fib_09_update_entry),
new_TestFixture(test_fib_10_add_exceed),
new_TestFixture(test_fib_11_get_next_hop_success),
new_TestFixture(test_fib_12_get_next_hop_fail),
new_TestFixture(test_fib_13_get_next_hop_fail_on_buffer_size),
new_TestFixture(test_fib_14_exact_and_prefix_match),
};
EMB_UNIT_TESTCALLER(fib_tests, NULL, NULL, fixtures);
return (Test *)&fib_tests;
}
void tests_fib(void)
{
TESTS_RUN(tests_fib_tests());
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2015 Martin Landsmann
*
* 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.
*/
/**
* @addtogroup unittests
* @{
*
* @file tests-fib.h
* @brief Unittests for the ``fib`` module
*
* @author Martin Landsmann <Martin.Landsmann@HAW-Hamburg.de>
*/
#ifndef TESTS_FIB_H_
#define TESTS_FIB_H_
#include "embUnit/embUnit.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief The entry point of this test suite.
*/
void tests_fib(void);
/**
* @brief Generates tests for FIB
*
* @return embUnit tests if successful, NULL if not.
*/
Test *tests_fib_tests(void);
#ifdef __cplusplus
}
#endif
#endif /* TESTS_FIB_H_ */
/** @} */