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:
commit
ece64548a6
@ -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
|
||||
*/
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.");
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user