Merge pull request #2818 from BytesGalore/fib_get_conditionlal_entry_set

sys/net/fib: added function to request a set of destination addresses
This commit is contained in:
Cenk Gündoğan 2015-06-05 22:07:22 +02:00
commit ece64548a6
6 changed files with 332 additions and 25 deletions

View File

@ -38,6 +38,20 @@ typedef struct rp_address_msg_t {
#define FIB_MSG_RP_SIGNAL (0x99) /**< message type for RP notifications */
/**
* @brief the size in bytes of a full address
* TODO: replace with UNIVERSAL_ADDRESS_SIZE (#3022)
*/
#define FIB_DESTINATION_SIZE_SUBSTITUTE (16)
/**
* @brief entry used to collect available destinations
*/
typedef struct fib_destination_set_entry_t {
uint8_t dest[FIB_DESTINATION_SIZE_SUBSTITUTE]; /**< The destination address */
size_t dest_size; /**< The destination address size */
} fib_destination_set_entry_t;
/**
* @brief indicator of a lifetime that does not expire (2^32 - 1)
*/
@ -130,6 +144,27 @@ 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 provides a set of destination addresses matching the given prefix
* If the out buffer is insufficient low or passed as NULL,
* the function will continue to count the number of matching entries
* and provide the number to the caller.
*
* @param[in] prefix the destination address
* @param[in] prefix_size the destination address size
* @param[out] dst_set the destination addresses matching the prefix
* @param[in, out] dst_size the number of entries available on in and used on out
*
* @return 0 on success
* -EHOSTUNREACH if no entry matches the type in the FIB
* -ENOBUFS if the size for the found entries is insufficient low
* The actual needed size is stored then in dst_set_size,
* however the required size may change in between calls.
*/
int fib_get_destination_set(uint8_t *prefix, size_t prefix_size,
fib_destination_set_entry_t *dst_set, size_t* dst_set_size);
/**
* @brief returns the actual number of used FIB entries
*/

View File

@ -82,19 +82,43 @@ uint8_t* universal_address_get_address(universal_address_container_t *entry,
/**
* @brief determines if the entry equals the provided address
* This function requires to be provided with the full size of the used
* address type behind *addr to be compareable with the address stored in *entry.
*
* @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
* @param[in, out] addr_size_in_bits the number of bits used for the address entry
* on sucessfull return this value is overwritten
* with the number of matching bits till the
* first of trailing `0`s
*
* @return 0 if the entries are equal or comperable
* @return 0 if the entries are equal
* 1 if the entry match to a certain prefix (trailing '0's in *entry)
* -ENOENT if the given adresses do not match
*/
int universal_address_compare(universal_address_container_t *entry,
uint8_t *addr, size_t *addr_size);
uint8_t *addr, size_t *addr_size_in_bits);
/**
* @brief determines if the entry equals the provided prefix
* This function requires to be provided with the full size of the used
* address type behind *prefix to be compareable with the address stored in *entry.
*
*
* @param[in] entry pointer to the universal_address_container_t for compare
* @param[in] prefix pointer to the address for compare
* @param[in] prefix_size_in_bits the number of bits used for the prefix entry.
* This size MUST be the full address size including trailing '0's,
* e.g. for an ng_ipv6_addr_t it would be sizeof(ng_ipv6_addr_t)
* regardless if the stored prefix is < ::/128
*
* @return 0 if the entries are equal
* 1 if the entry match to a certain prefix (trailing '0's in *prefix)
* -ENOENT if the given adresses do not match
*/
int universal_address_compare_prefix(universal_address_container_t *entry,
uint8_t *prefix, size_t prefix_size_in_bits);
/**
* @brief Prints the content of the given entry

View File

@ -98,7 +98,7 @@ static int fib_find_entry(uint8_t *dst, size_t dst_size,
size_t count = 0;
size_t prefix_size = 0;
size_t match_size = dst_size;
size_t match_size = dst_size<<3;
int ret = -EHOSTUNREACH;
bool is_all_zeros_addr = true;
@ -136,13 +136,11 @@ static int fib_find_entry(uint8_t *dst, size_t dst_size,
}
}
if ((prefix_size < dst_size) &&
(fib_table[i].global != NULL) &&
(universal_address_compare(fib_table[i].global, dst, &match_size) == 0)) {
if ((prefix_size < (dst_size<<3)) && (fib_table[i].global != NULL)) {
int ret_comp = universal_address_compare(fib_table[i].global, dst, &match_size);
/* If we found an exact match */
if (match_size == dst_size
|| (is_all_zeros_addr && match_size == 0)) {
if (ret_comp == 0 || (is_all_zeros_addr && match_size == 0)) {
entry_arr[0] = &(fib_table[i]);
*entry_arr_size = 1;
/* we will not find a better one so we return */
@ -150,16 +148,16 @@ static int fib_find_entry(uint8_t *dst, size_t dst_size,
}
else {
/* we try to find the most fitting prefix */
if (match_size > prefix_size) {
if (ret_comp == 1) {
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<<3;
count = 1;
}
}
prefix_size = match_size;
match_size = dst_size;
count = 1;
}
}
@ -412,7 +410,6 @@ int fib_get_next_hop(kernel_pid_t *iface_id,
fib_entry_t *entry[count];
int ret = fib_find_entry(dst, dst_size, &(entry[0]), &count);
if (!(ret == 0 || ret == 1)) {
/* notify all responsible RPs for unknown next-hop for the destination address */
if (fib_signal_rp(dst, dst_size, dst_flags) == 0) {
@ -443,6 +440,40 @@ int fib_get_next_hop(kernel_pid_t *iface_id,
return 0;
}
int fib_get_destination_set(uint8_t *prefix, size_t prefix_size,
fib_destination_set_entry_t *dst_set, size_t* dst_set_size)
{
mutex_lock(&mtx_access);
int ret = -EHOSTUNREACH;
size_t found_entries = 0;
for (size_t i = 0; i < FIB_MAX_FIB_TABLE_ENTRIES; ++i) {
if ((fib_table[i].global != NULL) &&
(universal_address_compare_prefix(fib_table[i].global, prefix, prefix_size<<3) >= 0)) {
if( (dst_set != NULL) && (found_entries < *dst_set_size) ) {
/* set the size to full byte usage */
dst_set[found_entries].dest_size = sizeof(dst_set[found_entries].dest);
universal_address_get_address(fib_table[i].global,
dst_set[found_entries].dest,
&dst_set[found_entries].dest_size);
}
found_entries++;
}
}
if( found_entries > *dst_set_size ) {
ret = -ENOBUFS;
} else if( found_entries > 0 ) {
ret = 0;
}
*dst_set_size = found_entries;
mutex_unlock(&mtx_access);
return ret;
}
void fib_init(void)
{
DEBUG("[fib_init] hello. Initializing some stuff.");

View File

@ -168,19 +168,19 @@ uint8_t* universal_address_get_address(universal_address_container_t *entry,
}
int universal_address_compare(universal_address_container_t *entry,
uint8_t *addr, size_t *addr_size)
uint8_t *addr, size_t *addr_size_in_bits)
{
mutex_lock(&mtx_access);
int ret = -ENOENT;
/* If we have distinct sizes, the addresses are probably not comperable */
if (entry->address_size != *addr_size) {
if ((size_t)(entry->address_size<<3) != *addr_size_in_bits) {
mutex_unlock(&mtx_access);
return ret;
}
/* Get the index of the first trailing `0` (indicates a network prefix) */
/* Get the index of the first trailing `0` (indicates a prefix) */
int i = 0;
for( i = entry->address_size-1; i >= 0; --i) {
if( entry->address[i] != 0 ) {
@ -188,9 +188,80 @@ int universal_address_compare(universal_address_container_t *entry,
}
}
if( memcmp(entry->address, addr, i+1) == 0 ) {
ret = 0;
*addr_size = i+1;
if( memcmp(entry->address, addr, i) == 0 ) {
/* if the bytes-1 equals we check the bits of the lowest byte */
uint8_t bitmask = 0x00;
uint8_t j = 0;
/* get a bitmask for the trailing 0b */
for( ; j < 8; ++j ) {
if ( (entry->address[i] >> j) & 0x01 ) {
bitmask = 0xff << j;
break;
}
}
if( (entry->address[i] & bitmask) == (addr[i] & bitmask) ) {
ret = entry->address[i] != addr[i];
*addr_size_in_bits = (i<<3) + j;
if( ret == 0 ) {
/* check if the remaining bits from addr are significant */
i++;
for(; i < entry->address_size; ++i) {
if( addr[i] != 0 ) {
ret = 1;
break;
}
}
}
}
}
mutex_unlock(&mtx_access);
return ret;
}
int universal_address_compare_prefix(universal_address_container_t *entry,
uint8_t *prefix, size_t prefix_size_in_bits)
{
mutex_lock(&mtx_access);
int ret = -ENOENT;
/* If we have distinct sizes, the prefix is not comperable */
if ((size_t)(entry->address_size<<3) != prefix_size_in_bits) {
mutex_unlock(&mtx_access);
return ret;
}
/* Get the index of the first trailing `0` */
int i = 0;
for( i = entry->address_size-1; i >= 0; --i) {
if( prefix[i] != 0 ) {
break;
}
}
if( memcmp(entry->address, prefix, i) == 0 ) {
/* if the bytes-1 equals we check the bits of the lowest byte */
uint8_t bitmask = 0x00;
/* get a bitmask for the trailing 0b */
for( uint8_t j = 0; j < 8; ++j ) {
if ( (prefix[i] >> j) & 0x01 ) {
bitmask = 0xff << j;
break;
}
}
if( (entry->address[i] & bitmask) == (prefix[i] & bitmask) ) {
ret = entry->address[i] != prefix[i];
if( ret == 0 ) {
/* check if the remaining bits from entry are significant */
i++;
for(; i < entry->address_size; ++i) {
if( entry->address[i] != 0 ) {
ret = 1;
break;
}
}
}
}
}
mutex_unlock(&mtx_access);

View File

@ -4,7 +4,7 @@ include ../Makefile.tests_common
BOARD_INSUFFICIENT_RAM := airfy-beacon chronos msb-430 msb-430h pca10000 \
pca10005 redbee-econotag spark-core stm32f0discovery \
telosb wsn430-v1_3b wsn430-v1_4 z1 nucleo-f334 \
yunjia-nrf51822
yunjia-nrf51822 samr21-xpro
USEMODULE += embunit

View File

@ -488,6 +488,7 @@ static void test_fib_14_exact_and_prefix_match(void)
fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x1234,
(uint8_t *)addr_nxt, add_buf_size - 1, 0x34, 100000);
memset(addr_lookup, 0, add_buf_size);
/* exact match */
snprintf(addr_lookup, add_buf_size, "Test addr123");
int ret = fib_get_next_hop(&iface_id,
@ -495,6 +496,7 @@ static void test_fib_14_exact_and_prefix_match(void)
(uint8_t *)addr_lookup, add_buf_size - 1, 0x123);
TEST_ASSERT_EQUAL_INT(0, ret);
add_buf_size = 16;
char addr_expect_01[] = "Test address 23";
ret = strncmp(addr_expect_01, addr_nxt, add_buf_size - 1);
@ -553,6 +555,148 @@ static void test_fib_15_get_lifetime(void)
TEST_ASSERT_EQUAL_INT(1, timex_cmp(lifetime, cmp_lifetime));
/* make sure lifetime hasn't grown magically either */
TEST_ASSERT_EQUAL_INT(-1, timex_cmp(lifetime, cmp_max_lifetime));
fib_deinit();
}
/*
* @brief testing prefix with bits
*/
static void test_fib_16_prefix_match(void)
{
size_t add_buf_size = 16;
char addr_dst[add_buf_size];
char addr_nxt[add_buf_size];
char addr_lookup[add_buf_size];
kernel_pid_t iface_id = KERNEL_PID_UNDEF;
uint32_t next_hop_flags = 0;
memset(addr_dst, 0, add_buf_size);
memset(addr_nxt, 0, add_buf_size);
memset(addr_lookup, 0, add_buf_size);
snprintf(addr_dst, add_buf_size, "Test address 1X");
snprintf(addr_nxt, add_buf_size, "Test address 99");
snprintf(addr_lookup, add_buf_size, "Test address 1X");
/* now we change the last byte of addr_dst to have defined trailing 0 bits */
/* test success */
addr_dst[14] = (char)0x80; /* 1000 0000 */
addr_lookup[14] = (char)0x87; /* 1000 0111 */
fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x123,
(uint8_t *)addr_nxt, add_buf_size - 1, 0x23, 100000);
addr_dst[14] = (char)0x3c; /* 0011 1100 */
fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x123,
(uint8_t *)addr_nxt, add_buf_size - 1, 0x23, 100000);
memset(addr_nxt, 0, add_buf_size);
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);
/* test fail */
addr_dst[14] = (char)0x3c; /* 0011 1100 */
addr_lookup[14] = (char)0x34; /* 0011 0100 */
add_buf_size = 16;
fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x123,
(uint8_t *)addr_nxt, add_buf_size - 1, 0x23, 100000);
memset(addr_nxt, 0, add_buf_size);
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(-EHOSTUNREACH, ret);
/* test success (again) by adjusting the lsb */
addr_lookup[14] = (char)0x3e; /* 0011 1110 */
add_buf_size = 16;
memset(addr_nxt, 0, add_buf_size);
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);
#if (TEST_FIB_SHOW_OUTPUT == 1)
fib_print_fib_table();
puts("");
universal_address_print_table();
puts("");
#endif
fib_deinit();
}
/*
* @brief testing receiving an destination address set matching a specific prefix
*/
static void test_fib_17_get_entry_set(void)
{
size_t addr_buf_size = 16;
char addr_dst[addr_buf_size];
char addr_nxt[addr_buf_size];
/* fill 20 addresses */
for (size_t i = 0; i < 20; ++i) {
/* construct "addresses" for the FIB */
snprintf(addr_dst, addr_buf_size, "Test address %02d", (int)i);
snprintf(addr_nxt, addr_buf_size, "Test address %02d", i % 11);
fib_add_entry(42, (uint8_t *)addr_dst, addr_buf_size - 1, 0x0,
(uint8_t *)addr_nxt, addr_buf_size - 1, 0x0, 100000);
}
size_t arr_size = 20;
fib_destination_set_entry_t arr_dst[arr_size];
char prefix[addr_buf_size];
memset(prefix,0, addr_buf_size);
snprintf(prefix, addr_buf_size, "Test address 1");
int ret = fib_get_destination_set((uint8_t *)prefix, addr_buf_size-1, &arr_dst[0], &arr_size);
TEST_ASSERT_EQUAL_INT(0, ret);
/* we should receive 10 entries 10 to 19 */
TEST_ASSERT_EQUAL_INT(10, arr_size);
arr_size = 20;
memset(prefix,0, addr_buf_size);
snprintf(prefix, addr_buf_size, "Test address 0");
ret = fib_get_destination_set((uint8_t *)prefix, addr_buf_size-1, &arr_dst[0], &arr_size);
TEST_ASSERT_EQUAL_INT(0, ret);
/* we should receive 20 entries 0-19 */
TEST_ASSERT_EQUAL_INT(20, arr_size);
arr_size = 20;
memset(prefix,0, addr_buf_size);
snprintf(prefix, addr_buf_size, "Test address");
ret = fib_get_destination_set((uint8_t *)prefix, addr_buf_size-1, &arr_dst[0], &arr_size);
TEST_ASSERT_EQUAL_INT(0, ret);
/* we should receive 20 entries 0-19 */
TEST_ASSERT_EQUAL_INT(20, arr_size);
#if (TEST_FIB_SHOW_OUTPUT == 1)
puts("");
for(size_t i = 0; i < arr_size; ++i) {
for( size_t j = 0; j < arr_dst[i].dest_size; ++j) {
printf("%c", (char)arr_dst[i].dest[j]);
}
puts("");
}
#endif
fib_deinit();
}
@ -575,6 +719,8 @@ Test *tests_fib_tests(void)
new_TestFixture(test_fib_13_get_next_hop_fail_on_buffer_size),
new_TestFixture(test_fib_14_exact_and_prefix_match),
new_TestFixture(test_fib_15_get_lifetime),
new_TestFixture(test_fib_16_prefix_match),
new_TestFixture(test_fib_17_get_entry_set),
};
EMB_UNIT_TESTCALLER(fib_tests, NULL, NULL, fixtures);