diff --git a/sys/net/routing/nhdp/iib_table.c b/sys/net/routing/nhdp/iib_table.c index a374aa7522..599d1ed183 100644 --- a/sys/net/routing/nhdp/iib_table.c +++ b/sys/net/routing/nhdp/iib_table.c @@ -24,11 +24,13 @@ #include "utlist.h" #include "kernel_types.h" +#include "rfc5444/rfc5444.h" #include "rfc5444/rfc5444_iana.h" #include "rfc5444/rfc5444_writer.h" #include "iib_table.h" #include "nhdp_address.h" +#include "nhdp_metric.h" #include "nhdp_writer.h" #define ENABLE_DEBUG (0) @@ -38,6 +40,10 @@ static mutex_t mtx_iib_access = MUTEX_INIT; static iib_base_entry_t *iib_base_entry_head = NULL; +#if (NHDP_METRIC == NHDP_LMT_DAT) +static const double const_dat = (((double)DAT_CONSTANT) / DAT_MAXIMUM_LOSS); +#endif + /* Internal function prototypes */ static void rem_link_set_entry(iib_base_entry_t *base_entry, iib_link_set_entry_t *ls_entry); static void cleanup_link_sets(void); @@ -64,6 +70,11 @@ static void rem_not_heard_nb_tuple(iib_link_set_entry_t *ls_entry, timex_t *now) static inline timex_t get_max_timex(timex_t time_one, timex_t time_two); static iib_link_tuple_status_t get_tuple_status(iib_link_set_entry_t *ls_entry, timex_t *now); +#if (NHDP_METRIC == NHDP_LMT_DAT) +static void queue_rem(uint8_t *queue); +static uint16_t queue_sum(uint8_t *queue); +static void dat_metric_refresh(void); +#endif /*---------------------------------------------------------------------------* * Interface Information Base API * @@ -86,10 +97,12 @@ int iib_register_if(kernel_pid_t pid) return 0; } -int iib_process_hello(kernel_pid_t if_pid, nib_entry_t *nb_elt, - uint64_t validity_time, uint8_t is_sym_nb, uint8_t is_lost) +iib_link_set_entry_t *iib_process_hello(kernel_pid_t if_pid, nib_entry_t *nb_elt, + uint64_t validity_time, uint8_t is_sym_nb, + uint8_t is_lost) { iib_base_entry_t *base_elt; + iib_link_set_entry_t *ls_entry = NULL; timex_t now; mutex_lock(&mtx_iib_access); @@ -108,8 +121,7 @@ int iib_process_hello(kernel_pid_t if_pid, nib_entry_t *nb_elt, vtimer_now(&now); /* Create a new link tuple for the neighbor that originated the hello */ - iib_link_set_entry_t *ls_entry = update_link_set(base_elt, nb_elt, &now, - validity_time, is_sym_nb, is_lost); + ls_entry = update_link_set(base_elt, nb_elt, &now, validity_time, is_sym_nb, is_lost); /* Create new two hop tuples for signaled symmetric neighbors */ if (ls_entry) { @@ -119,7 +131,7 @@ int iib_process_hello(kernel_pid_t if_pid, nib_entry_t *nb_elt, mutex_unlock(&mtx_iib_access); - return 0; + return ls_entry; } void iib_fill_wr_addresses(kernel_pid_t if_pid, struct rfc5444_writer *wr) @@ -149,14 +161,18 @@ void iib_fill_wr_addresses(kernel_pid_t if_pid, struct rfc5444_writer *wr) case IIB_LT_STATUS_SYM: nhdp_writer_add_addr(wr, addr_elt->address, RFC5444_ADDRTLV_LINK_STATUS, - RFC5444_LINKSTATUS_SYMMETRIC); + RFC5444_LINKSTATUS_SYMMETRIC, + rfc5444_metric_encode(ls_elt->metric_in), + rfc5444_metric_encode(ls_elt->metric_out)); addr_elt->address->in_tmp_table = NHDP_ADDR_TMP_SYM; break; case IIB_LT_STATUS_HEARD: nhdp_writer_add_addr(wr, addr_elt->address, RFC5444_ADDRTLV_LINK_STATUS, - RFC5444_LINKSTATUS_HEARD); + RFC5444_LINKSTATUS_HEARD, + rfc5444_metric_encode(ls_elt->metric_in), + rfc5444_metric_encode(ls_elt->metric_out)); addr_elt->address->in_tmp_table = NHDP_ADDR_TMP_ANY; break; @@ -166,7 +182,9 @@ void iib_fill_wr_addresses(kernel_pid_t if_pid, struct rfc5444_writer *wr) case IIB_LT_STATUS_LOST: nhdp_writer_add_addr(wr, addr_elt->address, RFC5444_ADDRTLV_LINK_STATUS, - RFC5444_LINKSTATUS_LOST); + RFC5444_LINKSTATUS_LOST, + rfc5444_metric_encode(ls_elt->metric_in), + rfc5444_metric_encode(ls_elt->metric_out)); addr_elt->address->in_tmp_table = NHDP_ADDR_TMP_ANY; break; @@ -216,6 +234,120 @@ void iib_propagate_nb_entry_change(nib_entry_t *old_entry, nib_entry_t *new_entr } } +void iib_process_metric_msg(iib_link_set_entry_t *ls_entry, uint64_t int_time) +{ +#if (NHDP_METRIC == NHDP_LMT_HOP_COUNT) + /* Hop metric value for an existing direct link is always 1 */ + (void)int_time; + ls_entry->metric_in = 1; + ls_entry->metric_out = 1; + if (ls_entry->nb_elt) { + ls_entry->nb_elt->metric_in = 1; + ls_entry->nb_elt->metric_out = 1; + } +#elif (NHDP_METRIC == NHDP_LMT_DAT) + /* Process required DAT metric steps */ + ls_entry->hello_interval = rfc5444_timetlv_encode(int_time); + if (ls_entry->last_seq_no == 0) { + timex_t now, i_time; + vtimer_now(&now); + i_time = timex_from_uint64(int_time * MS_IN_USEC * DAT_HELLO_TIMEOUT_FACTOR); + ls_entry->dat_received[0]++; + ls_entry->dat_total[0]++; + ls_entry->dat_time = timex_add(now, i_time); + } +#else + /* NHDP_METRIC is not set properly */ + (void)ls_entry; + (void)int_time; + DEBUGF("[WARNING] Unknown NHDP_METRIC setting\n"); +#endif +} + +void iib_process_metric_pckt(iib_link_set_entry_t *ls_entry, uint32_t metric_out, uint16_t seq_no) +{ +#if (NHDP_METRIC == NHDP_LMT_HOP_COUNT) + /* Nothing to do here */ + (void)ls_entry; + (void)metric_out; + (void)seq_no; +#elif (NHDP_METRIC == NHDP_LMT_DAT) + /* Metric packet processing */ + if (ls_entry->last_seq_no == 0) { + ls_entry->dat_received[0] = 1; + ls_entry->dat_total[0] = 1; + } + /* Don't add values to the queue for duplicate packets */ + else if (seq_no != ls_entry->last_seq_no) { + uint16_t seq_diff; + if (seq_no < ls_entry->last_seq_no) { + seq_diff = (uint16_t) ((((uint32_t) seq_no) + 0xFFFF) - ls_entry->last_seq_no); + } + else { + seq_diff = seq_no - ls_entry->last_seq_no; + } + ls_entry->dat_total[0] += (seq_diff > NHDP_SEQNO_RESTART_DETECT) ? 1 : seq_diff; + ls_entry->dat_received[0]++; + } + + ls_entry->last_seq_no = seq_no; + ls_entry->lost_hellos = 0; + + if (ls_entry->hello_interval != 0) { + timex_t now, i_time; + vtimer_now(&now); + i_time = timex_from_uint64(rfc5444_timetlv_decode(ls_entry->hello_interval) + * MS_IN_USEC * DAT_HELLO_TIMEOUT_FACTOR); + ls_entry->dat_time = timex_add(now, i_time); + } + + /* Refresh metric value for link tuple and corresponding neighbor tuple */ + if (ls_entry->nb_elt) { + if ((metric_out <= ls_entry->nb_elt->metric_out) || + (ls_entry->nb_elt->metric_out == NHDP_METRIC_UNKNOWN)) { + /* Better value, use it also for your neighbor */ + ls_entry->nb_elt->metric_out = metric_out; + } + else if (ls_entry->metric_out == ls_entry->nb_elt->metric_out){ + /* The corresponding neighbor tuples metric needs to be updated */ + iib_base_entry_t *base_elt; + iib_link_set_entry_t *ls_elt; + ls_entry->nb_elt->metric_out = metric_out; + LL_FOREACH(iib_base_entry_head, base_elt) { + LL_FOREACH(base_elt->link_set_head, ls_elt) { + if ((ls_elt->nb_elt == ls_entry->nb_elt) && (ls_elt != ls_entry)) { + if (ls_elt->metric_out < ls_entry->nb_elt->metric_out) { + /* Smaller DAT value is better */ + ls_entry->nb_elt->metric_out = ls_elt->metric_out; + } + break; + } + } + } + } + } + ls_entry->metric_out = metric_out; +#else + /* NHDP_METRIC is not set properly */ + (void)ls_entry; + (void)metric_out; + (void)seq_no; + DEBUGF("[WARNING] Unknown NHDP_METRIC setting\n"); +#endif +} + +void iib_process_metric_refresh(void) +{ +#if (NHDP_METRIC == NHDP_LMT_HOP_COUNT) + /* Nothing to do here */ +#elif (NHDP_METRIC == NHDP_LMT_DAT) + dat_metric_refresh(); +#else + /* NHDP_METRIC is not set properly */ + DEBUGF("[WARNING] Unknown NHDP_METRIC setting\n"); +#endif +} + /*------------------------------------------------------------------------------------*/ /* Internal functions */ @@ -427,7 +559,6 @@ static iib_link_set_entry_t *add_default_link_set_entry(iib_base_entry_t *base_e uint64_t val_time) { iib_link_set_entry_t *new_entry; - timex_t v_time = timex_from_uint64(val_time * MS_IN_USEC); new_entry = (iib_link_set_entry_t *) malloc(sizeof(iib_link_set_entry_t)); @@ -437,15 +568,7 @@ static iib_link_set_entry_t *add_default_link_set_entry(iib_base_entry_t *base_e } new_entry->address_list_head = NULL; - new_entry->heard_time.microseconds = 0; - new_entry->heard_time.seconds = 0; - new_entry->sym_time.microseconds = 0; - new_entry->sym_time.seconds = 0; - new_entry->pending = NHDP_INITIAL_PENDING; - new_entry->lost = 0; - new_entry->exp_time = timex_add(*now, v_time); - new_entry->last_status = IIB_LT_STATUS_UNKNOWN; - new_entry->nb_elt = NULL; + reset_link_set_entry(new_entry, now, val_time); LL_PREPEND(base_entry->link_set_head, new_entry); return new_entry; @@ -468,6 +591,18 @@ static void reset_link_set_entry(iib_link_set_entry_t *ls_entry, timex_t *now, u ls_entry->exp_time = timex_add(*now, v_time); ls_entry->nb_elt = NULL; ls_entry->last_status = IIB_LT_STATUS_UNKNOWN; + ls_entry->metric_in = NHDP_METRIC_UNKNOWN; + ls_entry->metric_out = NHDP_METRIC_UNKNOWN; +#if (NHDP_METRIC == NHDP_LMT_DAT) + memset(ls_entry->dat_received, 0, NHDP_Q_MEM_LENGTH); + memset(ls_entry->dat_total, 0, NHDP_Q_MEM_LENGTH); + ls_entry->dat_time.microseconds = 0; + ls_entry->dat_time.seconds = 0; + ls_entry->hello_interval = 0; + ls_entry->lost_hellos = 0; + ls_entry->rx_bitrate = 100000; + ls_entry->last_seq_no = 0; +#endif } /** @@ -554,6 +689,15 @@ static int add_two_hop_entry(iib_base_entry_t *base_entry, iib_link_set_entry_t new_entry->th_nb_addr = th_addr; new_entry->ls_elt = ls_entry; new_entry->exp_time = timex_add(*now, v_time); + if (th_addr->tmp_metric_val != NHDP_METRIC_UNKNOWN) { + new_entry->metric_in = rfc5444_metric_decode(th_addr->tmp_metric_val); + new_entry->metric_out = rfc5444_metric_decode(th_addr->tmp_metric_val); + } + else { + new_entry->metric_in = NHDP_METRIC_UNKNOWN; + new_entry->metric_out = NHDP_METRIC_UNKNOWN; + } + LL_PREPEND(base_entry->two_hop_set_head, new_entry); return 0; @@ -665,3 +809,111 @@ static inline timex_t get_max_timex(timex_t time_one, timex_t time_two) return time_two; } + +#if (NHDP_METRIC == NHDP_LMT_DAT) +/** + * Sum all elements in the queue + */ +static uint16_t queue_sum(uint8_t *queue) +{ + uint16_t sum = 0; + + for (int i = 0; i < NHDP_Q_MEM_LENGTH; i++) { + sum += queue[i]; + } + + return sum; +} + +/** + * Remove the oldest element in the queue + */ +static void queue_rem(uint8_t *queue) +{ + uint8_t temp; + uint8_t prev_value = queue[0]; + + /* Clear spot for a new element */ + queue[0] = 0; + + /* Shift elements */ + for (int i = 1; i < NHDP_Q_MEM_LENGTH; i++) { + temp = queue[i]; + queue[i] = prev_value; + prev_value = temp; + } +} + +/** + * Update DAT metric values for all Link Tuples + */ +static void dat_metric_refresh(void) +{ + iib_base_entry_t *base_elt; + iib_link_set_entry_t *ls_elt; + uint32_t metric_temp; + double sum_total, sum_rcvd, loss; + + LL_FOREACH(iib_base_entry_head, base_elt) { + LL_FOREACH(base_elt->link_set_head, ls_elt) { + sum_rcvd = queue_sum(ls_elt->dat_received); + sum_total = queue_sum(ls_elt->dat_total); + metric_temp = ls_elt->metric_in; + + if ((ls_elt->hello_interval != 0) && (ls_elt->lost_hellos > 0)) { + /* Compute lost time proportion */ + loss = (((double)ls_elt->hello_interval) * ((double)ls_elt->lost_hellos)) + / DAT_MEMORY_LENGTH; + if (loss >= 1.0) { + sum_rcvd = 0.0; + } + else { + sum_rcvd *= (1.0 - loss); + } + } + + if (sum_rcvd < 1.0) { + ls_elt->metric_in = NHDP_METRIC_MAXIMUM; + } + else { + loss = sum_total / sum_rcvd; + if (loss > DAT_MAXIMUM_LOSS) { + loss = DAT_MAXIMUM_LOSS; + } + ls_elt->metric_in = (const_dat * loss) / (ls_elt->rx_bitrate / DAT_MINIMUM_BITRATE); + if (ls_elt->metric_in > NHDP_METRIC_MAXIMUM) { + ls_elt->metric_in = NHDP_METRIC_MAXIMUM; + } + } + + if (ls_elt->nb_elt) { + if (ls_elt->metric_in <= ls_elt->nb_elt->metric_in || + (ls_elt->nb_elt->metric_in == NHDP_METRIC_UNKNOWN)) { + /* Better value, use it also for your neighbor */ + ls_elt->nb_elt->metric_in = ls_elt->metric_in; + } + else if (metric_temp == ls_elt->nb_elt->metric_in){ + /* The corresponding neighbor tuples metric needs to be updated */ + iib_base_entry_t *base_entry; + iib_link_set_entry_t *ls_entry; + ls_elt->nb_elt->metric_in = ls_elt->metric_in; + LL_FOREACH(iib_base_entry_head, base_entry) { + LL_FOREACH(base_entry->link_set_head, ls_entry) { + if ((ls_elt->nb_elt == ls_entry->nb_elt) && (ls_elt != ls_entry)) { + if (ls_entry->metric_in < ls_elt->nb_elt->metric_in) { + /* Smaller DAT value is better */ + ls_elt->nb_elt->metric_in = ls_entry->metric_in; + } + break; + } + } + } + } + } + + queue_rem(ls_elt->dat_received); + queue_rem(ls_elt->dat_total); + } + } +} +#endif diff --git a/sys/net/routing/nhdp/iib_table.h b/sys/net/routing/nhdp/iib_table.h index 8429bf30bf..4776b9c498 100644 --- a/sys/net/routing/nhdp/iib_table.h +++ b/sys/net/routing/nhdp/iib_table.h @@ -24,6 +24,7 @@ #include "nib_table.h" #include "nhdp_address.h" +#include "nhdp_metric.h" #ifdef __cplusplus extern "C" { @@ -52,6 +53,17 @@ typedef struct iib_link_set_entry_t { timex_t exp_time; /**< Time at which entry expires */ nib_entry_t *nb_elt; /**< Pointer to corresponding nb tuple */ enum iib_link_tuple_status_t last_status; /**< Last processed status of link tuple */ + uint32_t metric_in; /**< Metric value for incoming link */ + uint32_t metric_out; /**< Metric value for outgoing link */ +#if (NHDP_METRIC == NHDP_LMT_DAT) + uint8_t dat_received[NHDP_Q_MEM_LENGTH]; /**< Queue for containing sums of rcvd packets */ + uint8_t dat_total[NHDP_Q_MEM_LENGTH]; /**< Queue for containing sums of xpctd packets */ + timex_t dat_time; /**< Time next HELLO is expected */ + uint8_t hello_interval; /**< Encoded HELLO interval value */ + uint8_t lost_hellos; /**< Lost HELLO count after last received HELLO */ + uint32_t rx_bitrate; /**< Incoming Bitrate for this link in Bit/s */ + uint16_t last_seq_no; /**< The last received packet sequence number */ +#endif struct iib_link_set_entry_t *next; /**< Pointer to next list entry */ } iib_link_set_entry_t; @@ -62,6 +74,8 @@ typedef struct iib_two_hop_set_entry_t { struct iib_link_set_entry_t *ls_elt; /**< Pointer to corresponding link tuple */ nhdp_addr_t *th_nb_addr; /**< Address of symmetric 2-hop neighbor */ timex_t exp_time; /**< Time at which entry expires */ + uint32_t metric_in; /**< Metric value for incoming link */ + uint32_t metric_out; /**< Metric value for outgoing link */ struct iib_two_hop_set_entry_t *next; /**< Pointer to next list entry */ } iib_two_hop_set_entry_t; @@ -100,10 +114,12 @@ int iib_register_if(kernel_pid_t pid); * @param[in] is_sym_nb Flag whether the link to the originator is symmetric * @param[in] is_lost Flag whether the originator marked this link as lost * - * @return 0 on success + * @return Pointer to the new or updated Link Tuple + * @return NULL on error */ -int iib_process_hello(kernel_pid_t if_pid, nib_entry_t *nb_elt, - uint64_t validity_time, uint8_t is_sym_nb, uint8_t is_lost); +iib_link_set_entry_t *iib_process_hello(kernel_pid_t if_pid, nib_entry_t *nb_elt, + uint64_t validity_time, uint8_t is_sym_nb, + uint8_t is_lost); /** * @brief Add addresses to the currently constructed HELLO message @@ -137,6 +153,34 @@ void iib_update_lt_status(timex_t *now); */ void iib_propagate_nb_entry_change(nib_entry_t *old_entry, nib_entry_t *new_entry); +/** + * @brief Process steps for the chosen NHDP metric for a message + * + * @note + * Must not be called from outside the NHDP reader's message processing. + * + * @param[in] ls_entry Pointer to the Link Tuple that needs to be updated + * @param[in] int_time Interval time in milliseconds for the originator's HELLO + */ +void iib_process_metric_msg(iib_link_set_entry_t *ls_entry, uint64_t int_time); + +/** + * @brief Process steps for the chosen NHDP metric for a packet + * + * @note + * Must not be called from outside the NHDP reader's packet processing. + * + * @param[in] ls_entry Pointer to the Link Tuple that needs to be updated + * @param[in] metric_out Metric value for outgoing link direction + * @param[in] seq_no The sequence number from the received packet + */ +void iib_process_metric_pckt(iib_link_set_entry_t *ls_entry, uint32_t metric_out, uint16_t seq_no); + +/** + * @brief Update metric values for the chosen NHDP metric for all Link Tuples + */ +void iib_process_metric_refresh(void); + #ifdef __cplusplus } #endif diff --git a/sys/net/routing/nhdp/lib_table.c b/sys/net/routing/nhdp/lib_table.c index c35e1c684c..401384a197 100644 --- a/sys/net/routing/nhdp/lib_table.c +++ b/sys/net/routing/nhdp/lib_table.c @@ -109,7 +109,8 @@ void lib_fill_wr_addresses(kernel_pid_t if_pid, struct rfc5444_writer *wr) if (lib_elt->if_pid == if_pid) { LL_FOREACH(lib_elt->if_addr_list_head, add_tmp) { nhdp_writer_add_addr(wr, add_tmp->address, - RFC5444_ADDRTLV_LOCAL_IF, RFC5444_LOCALIF_THIS_IF); + RFC5444_ADDRTLV_LOCAL_IF, RFC5444_LOCALIF_THIS_IF, + NHDP_METRIC_UNKNOWN, NHDP_METRIC_UNKNOWN); add_tmp->address->in_tmp_table = NHDP_ADDR_TMP_ANY; } break; @@ -124,7 +125,8 @@ void lib_fill_wr_addresses(kernel_pid_t if_pid, struct rfc5444_writer *wr) if (!NHDP_ADDR_TMP_IN_ANY(add_tmp->address)) { /* Address can be added */ nhdp_writer_add_addr(wr, add_tmp->address, - RFC5444_ADDRTLV_LOCAL_IF, RFC5444_LOCALIF_OTHER_IF); + RFC5444_ADDRTLV_LOCAL_IF, RFC5444_LOCALIF_OTHER_IF, + NHDP_METRIC_UNKNOWN, NHDP_METRIC_UNKNOWN); add_tmp->address->in_tmp_table = NHDP_ADDR_TMP_ANY; } } diff --git a/sys/net/routing/nhdp/nhdp.c b/sys/net/routing/nhdp/nhdp.c index 2e66fcb917..d460694f45 100644 --- a/sys/net/routing/nhdp/nhdp.c +++ b/sys/net/routing/nhdp/nhdp.c @@ -47,6 +47,11 @@ static mutex_t send_rcv_mutex = MUTEX_INIT; static sockaddr6_t sa_bcast; static int sock_rcv; +#if (NHDP_METRIC_NEEDS_TIMER) +static vtimer_t metric_timer; +static timex_t metric_interval; +#endif + /* Internal function prototypes */ static void *_nhdp_runner(void *arg __attribute__((unused))); static void *_nhdp_receiver(void *arg __attribute__((unused))); @@ -90,6 +95,14 @@ kernel_pid_t nhdp_start(void) /* Start the NHDP thread */ nhdp_pid = thread_create(nhdp_stack, sizeof(nhdp_stack), THREAD_PRIORITY_MAIN - 1, CREATE_STACKTEST, _nhdp_runner, NULL, "NHDP"); + +#if (NHDP_METRIC_NEEDS_TIMER) + /* Configure periodic timer message to refresh metric values */ + if (nhdp_pid != KERNEL_PID_UNDEF) { + metric_interval = timex_from_uint64(DAT_REFRESH_INTERVAL * SEC_IN_USEC); + vtimer_set_msg(&metric_timer, metric_interval, nhdp_pid, NHDP_METRIC_TIMER, NULL); + } +#endif } return nhdp_pid; @@ -248,6 +261,18 @@ static void *_nhdp_runner(void *arg) mutex_unlock(&send_rcv_mutex); break; +#if (NHDP_METRIC_NEEDS_TIMER) + case NHDP_METRIC_TIMER: + mutex_lock(&send_rcv_mutex); + /* Process necessary metric computations */ + iib_process_metric_refresh(); + + /* Schedule next sending */ + vtimer_set_msg(&metric_timer, metric_interval, + thread_getpid(), NHDP_METRIC_TIMER, NULL); + mutex_unlock(&send_rcv_mutex); + break; +#endif default: break; } diff --git a/sys/net/routing/nhdp/nhdp.h b/sys/net/routing/nhdp/nhdp.h index c3e54326e1..eeb6e276f0 100644 --- a/sys/net/routing/nhdp/nhdp.h +++ b/sys/net/routing/nhdp/nhdp.h @@ -25,6 +25,7 @@ #include "kernel_types.h" #include "socket_base/socket.h" +#include "nhdp_metric.h" #include "rfc5444/rfc5444_writer.h" #ifdef __cplusplus diff --git a/sys/net/routing/nhdp/nhdp_address.c b/sys/net/routing/nhdp/nhdp_address.c index a9784aff4e..ef8bd6e49a 100644 --- a/sys/net/routing/nhdp/nhdp_address.c +++ b/sys/net/routing/nhdp/nhdp_address.c @@ -71,6 +71,7 @@ nhdp_addr_t *nhdp_addr_db_get_address(uint8_t *addr, size_t addr_size, uint8_t a addr_elt->addr_type = addr_type; addr_elt->usg_count = 0; addr_elt->in_tmp_table = NHDP_ADDR_TMP_NONE; + addr_elt->tmp_metric_val = NHDP_METRIC_UNKNOWN; LL_PREPEND(nhdp_addr_db_head, addr_elt); } @@ -146,6 +147,7 @@ void nhdp_reset_addresses_tmp_usg(uint8_t decr_usg) nhdp_addr_t *addr_elt, *addr_tmp; LL_FOREACH_SAFE(nhdp_addr_db_head, addr_elt, addr_tmp) { + addr_elt->tmp_metric_val = NHDP_METRIC_UNKNOWN; if (addr_elt->in_tmp_table) { addr_elt->in_tmp_table = NHDP_ADDR_TMP_NONE; if (decr_usg) { diff --git a/sys/net/routing/nhdp/nhdp_address.h b/sys/net/routing/nhdp/nhdp_address.h index 660f08efc1..29bed62ee5 100644 --- a/sys/net/routing/nhdp/nhdp_address.h +++ b/sys/net/routing/nhdp/nhdp_address.h @@ -32,6 +32,7 @@ typedef struct nhdp_addr_t { uint8_t addr_type; /**< AF type for the address */ uint8_t usg_count; /**< Usage count in information bases */ uint8_t in_tmp_table; /**< Signals usage in a writers temp table */ + uint16_t tmp_metric_val; /**< Encoded metric value used during HELLO processing */ struct nhdp_addr_t *next; /**< Pointer to next address (used in central storage) */ } nhdp_addr_t; diff --git a/sys/net/routing/nhdp/nhdp_metric.h b/sys/net/routing/nhdp/nhdp_metric.h new file mode 100644 index 0000000000..9ea5232fd6 --- /dev/null +++ b/sys/net/routing/nhdp/nhdp_metric.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 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. + */ + +/** + * @ingroup nhdp + * @{ + * + * @file + * @brief Macros for NHDP metric computation + * + * The used infrastructure for exchanging metric values is based on the rules defined in the RFC + * of OLSRv2. The calculations for the + * Directional Airtime Metric (DAT) are based on + * DAT Draft v5. + * + * @author Fabian Nack + */ + +#ifndef NHDP_METRIC_H_ +#define NHDP_METRIC_H_ + +#include "rfc5444/rfc5444.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name NHDP protocol macros + * + * @{ + */ +/** @brief Hop Count metric extension value for metric TLV extension field */ +#define NHDP_LMT_HOP_COUNT (163) +/** @brief DAT metric extension value for metric TLV extension field */ +#define NHDP_LMT_DAT (165) + +/** @brief Used metric (change to switch to another metric type) */ +#define NHDP_METRIC (NHDP_LMT_HOP_COUNT) + +/** @brief Randomly chosen number for NHDP's metric timer event */ +#define NHDP_METRIC_TIMER (5445) +/** @brief Macro controlling the start of a periodic timer event for matric computation */ +#define NHDP_METRIC_NEEDS_TIMER (NHDP_METRIC == NHDP_LMT_DAT) + +#define NHDP_METRIC_UNKNOWN (0) +#define NHDP_METRIC_MINIMUM (RFC5444_METRIC_MIN) +#define NHDP_METRIC_MAXIMUM (RFC5444_METRIC_MAX) + +/** @brief Default queue size for metrics using a queue to determine link loss */ +#define NHDP_Q_MEM_LENGTH (64) +/** @brief Restart detection value for packet sequence number based link loss computation */ +#define NHDP_SEQNO_RESTART_DETECT (256) + +/** @brief Encoding for an incoming link metric value in metric TLV */ +#define NHDP_KD_LM_INC (0x8000) +/** @brief Encoding for an outgoing link metric value in metric TLV */ +#define NHDP_KD_LM_OUT (0x4000) +/** @brief Encoding for an incoming neighbor metric value in metric TLV */ +#define NHDP_KD_NM_INC (0x2000) +/** @brief Encoding for an outgoing neighbor metric value in metric TLV */ +#define NHDP_KD_NM_OUT (0x1000) +/** @} */ + +/** + * @name DAT metric specific macros + * + * @{ + */ +/** @brief Length of RCVD and TOTAL queue of DAT metric */ +#define DAT_MEMORY_LENGTH (NHDP_Q_MEM_LENGTH) +/** @brief Time between DAT metric refreshal */ +#define DAT_REFRESH_INTERVAL (1) +/** @brief Factor to spread HELLO interval */ +#define DAT_HELLO_TIMEOUT_FACTOR (1.2) +/** @brief Minimal supported bit rate in bps (default value for new links) */ +#define DAT_MINIMUM_BITRATE (1000) +/** @brief Maximum allowed loss in expected/rcvd HELLOs (should not be changed) */ +#define DAT_MAXIMUM_LOSS (8) +/** @brief Constant value needed for DAT metric computation (should not be changed) */ +#define DAT_CONSTANT (16777216) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* NHDP_METRIC_H_ */ diff --git a/sys/net/routing/nhdp/nhdp_reader.c b/sys/net/routing/nhdp/nhdp_reader.c index 88b12c2b54..c19ab0e848 100644 --- a/sys/net/routing/nhdp/nhdp_reader.c +++ b/sys/net/routing/nhdp/nhdp_reader.c @@ -36,6 +36,9 @@ struct rfc5444_reader reader; static mutex_t mtx_packet_handler = MUTEX_INIT; +static iib_link_set_entry_t *originator_link_tuple = NULL; +static uint32_t lt_metric_val = NHDP_METRIC_UNKNOWN; + static kernel_pid_t if_pid; static uint64_t val_time; static uint64_t int_time; @@ -43,6 +46,8 @@ static uint8_t sym = 0; static uint8_t lost = 0; /* Internal function prototypes */ +static enum rfc5444_result _nhdp_pkt_end_cb(struct rfc5444_reader_tlvblock_context *context, + bool dropped); static enum rfc5444_result _nhdp_blocktlv_msg_cb(struct rfc5444_reader_tlvblock_context *cont); static enum rfc5444_result _nhdp_blocktlv_address_cb(struct rfc5444_reader_tlvblock_context *cont); static enum rfc5444_result _nhdp_msg_end_cb(struct rfc5444_reader_tlvblock_context *cont, @@ -50,6 +55,7 @@ static enum rfc5444_result _nhdp_msg_end_cb(struct rfc5444_reader_tlvblock_conte static enum rfc5444_result check_msg_validity(struct rfc5444_reader_tlvblock_context *cont); static enum rfc5444_result check_addr_validity(nhdp_addr_t *addr); static nhdp_addr_t *get_nhdp_db_addr(uint8_t *addr, uint8_t prefix); +static void add_temp_metric_value(nhdp_addr_t *address); static void process_temp_tables(void); /* Array containing the processable message TLVs for HELLO messages */ @@ -63,6 +69,14 @@ static struct rfc5444_reader_tlvblock_consumer_entry _nhdp_addr_tlvs[] = { [RFC5444_ADDRTLV_LOCAL_IF] = { .type = RFC5444_ADDRTLV_LOCAL_IF }, [RFC5444_ADDRTLV_LINK_STATUS] = { .type = RFC5444_ADDRTLV_LINK_STATUS }, [RFC5444_ADDRTLV_OTHER_NEIGHB] = { .type = RFC5444_ADDRTLV_OTHER_NEIGHB }, + [RFC5444_ADDRTLV_LINK_METRIC] = { .type = RFC5444_ADDRTLV_LINK_METRIC, .type_ext = NHDP_METRIC, + .match_type_ext = true, .min_length = 0x02, + .max_length = 0x02, .match_length = true }, +}; + +/* oonf_api packet consumer used for RFC5444 packet consumption */ +static struct rfc5444_reader_tlvblock_consumer _nhdp_packet_consumer = { + .end_callback = _nhdp_pkt_end_cb, }; /* oonf_api message consumer used for HELLO message consumption */ @@ -89,6 +103,9 @@ void nhdp_reader_init(void) /* Initialize reader */ rfc5444_reader_init(&reader); + /* Register packet consumer for sequence number processing */ + rfc5444_reader_add_packet_consumer(&reader, &_nhdp_packet_consumer, NULL, 0); + /* Register HELLO message consumer */ rfc5444_reader_add_message_consumer(&reader, &_nhdp_msg_consumer, _nhdp_msg_tlvs, ARRAYSIZE(_nhdp_msg_tlvs)); @@ -122,6 +139,25 @@ void nhdp_reader_cleanup(void) /* Internal functions */ /*------------------------------------------------------------------------------------*/ +/** + * Process metric steps for packet with packet sequence number + * Called by oonf_api after the whole packet was processed + */ +static enum rfc5444_result _nhdp_pkt_end_cb(struct rfc5444_reader_tlvblock_context *context, + bool dropped __attribute__((unused))) +{ + /* Process metric changes */ + if ((originator_link_tuple != NULL) && (context->has_pktseqno)) { + iib_process_metric_pckt(originator_link_tuple, lt_metric_val, context->pkt_seqno); + } + + /* Reset originator temp fields */ + originator_link_tuple = NULL; + lt_metric_val = NHDP_METRIC_UNKNOWN; + + return RFC5444_OKAY; +} + /** * Handle one address and its corresponding TLVs * Called by oonf_api for every included address to allow parsing @@ -186,12 +222,24 @@ _nhdp_blocktlv_address_cb(struct rfc5444_reader_tlvblock_context *cont) } } + if (lt_metric_val == NHDP_METRIC_UNKNOWN + && _nhdp_addr_tlvs[RFC5444_ADDRTLV_LINK_METRIC].tlv != NULL) { + /* Determine our outgoing link metric value to the originator interface */ + uint16_t metric_enc = *((uint16_t*)_nhdp_addr_tlvs[RFC5444_ADDRTLV_LINK_METRIC] + .tlv->single_value); + if (metric_enc & NHDP_KD_LM_INC) { + /* Incoming metric value at the neighbor if is outgoing value for our if */ + lt_metric_val = rfc5444_metric_decode(metric_enc); + } + } + /* Address is one of our own addresses, ignore it */ nhdp_decrement_addr_usage(current_addr); } else if (_nhdp_addr_tlvs[RFC5444_ADDRTLV_LINK_STATUS].tlv) { switch (*_nhdp_addr_tlvs[RFC5444_ADDRTLV_LINK_STATUS].tlv->single_value) { case RFC5444_LINKSTATUS_SYMMETRIC: + add_temp_metric_value(current_addr); current_addr->in_tmp_table = NHDP_ADDR_TMP_TH_SYM_LIST; break; @@ -203,6 +251,7 @@ _nhdp_blocktlv_address_cb(struct rfc5444_reader_tlvblock_context *cont) && *_nhdp_addr_tlvs[RFC5444_ADDRTLV_OTHER_NEIGHB].tlv->single_value == RFC5444_OTHERNEIGHB_SYMMETRIC) { /* Symmetric has higher priority */ + add_temp_metric_value(current_addr); current_addr->in_tmp_table = NHDP_ADDR_TMP_TH_SYM_LIST; } else { @@ -220,6 +269,7 @@ _nhdp_blocktlv_address_cb(struct rfc5444_reader_tlvblock_context *cont) else if (_nhdp_addr_tlvs[RFC5444_ADDRTLV_OTHER_NEIGHB].tlv) { switch (*_nhdp_addr_tlvs[RFC5444_ADDRTLV_OTHER_NEIGHB].tlv->single_value) { case RFC5444_OTHERNEIGHB_SYMMETRIC: + add_temp_metric_value(current_addr); current_addr->in_tmp_table = NHDP_ADDR_TMP_TH_SYM_LIST; break; @@ -384,6 +434,20 @@ static nhdp_addr_t *get_nhdp_db_addr(uint8_t *addr, uint8_t prefix) } } +/** + * Add a metric value to the address if a corresponding TLV exists in the message + */ +static void add_temp_metric_value(nhdp_addr_t *address) +{ + if (_nhdp_addr_tlvs[RFC5444_ADDRTLV_LINK_METRIC].tlv) { + uint16_t metric_enc = *((uint16_t*)_nhdp_addr_tlvs[RFC5444_ADDRTLV_LINK_METRIC] + .tlv->single_value); + if (metric_enc & (NHDP_KD_LM_INC | NHDP_KD_NM_INC)) { + address->tmp_metric_val = metric_enc; + } + } +} + /** * Process address lists from the HELLO msg in the information bases */ @@ -398,6 +462,10 @@ static void process_temp_tables(void) nib_elt = nib_process_hello(); if (nib_elt) { - iib_process_hello(if_pid, nib_elt, val_time, sym, lost); + originator_link_tuple = iib_process_hello(if_pid, nib_elt, val_time, sym, lost); + + if (originator_link_tuple) { + iib_process_metric_msg(originator_link_tuple, int_time != 0 ? int_time : val_time); + } } } diff --git a/sys/net/routing/nhdp/nhdp_writer.c b/sys/net/routing/nhdp/nhdp_writer.c index efada302d1..3de3b7e961 100644 --- a/sys/net/routing/nhdp/nhdp_writer.c +++ b/sys/net/routing/nhdp/nhdp_writer.c @@ -55,6 +55,7 @@ static struct rfc5444_writer_tlvtype _nhdp_addrtlvs[] = { [RFC5444_ADDRTLV_LOCAL_IF] = { .type = RFC5444_ADDRTLV_LOCAL_IF }, [RFC5444_ADDRTLV_LINK_STATUS] = { .type = RFC5444_ADDRTLV_LINK_STATUS }, [RFC5444_ADDRTLV_OTHER_NEIGHB] = { .type = RFC5444_ADDRTLV_OTHER_NEIGHB }, + [RFC5444_ADDRTLV_LINK_METRIC] = { .type = RFC5444_ADDRTLV_LINK_METRIC, .exttype = NHDP_METRIC } }; /* Writer content provider for HELLO messages */ @@ -134,7 +135,8 @@ void nhdp_writer_send_hello(nhdp_if_entry_t *if_entry) } void nhdp_writer_add_addr(struct rfc5444_writer *wr, nhdp_addr_t *addr, - enum rfc5444_addrtlv_iana type, uint8_t value) + enum rfc5444_addrtlv_iana type, uint8_t value, + uint16_t metric_in, uint16_t metric_out) { struct rfc5444_writer_address *wr_addr; struct netaddr n_addr; @@ -164,6 +166,25 @@ void nhdp_writer_add_addr(struct rfc5444_writer *wr, nhdp_addr_t *addr, rfc5444_writer_add_addrtlv(wr, wr_addr, &_nhdp_addrtlvs[type], &value, sizeof(uint8_t), false); + + /* Add LINK_METRIC TLV if necessary */ + if ((NHDP_METRIC == NHDP_LMT_DAT) && (metric_in != NHDP_METRIC_UNKNOWN)) { + switch(type) { + case RFC5444_ADDRTLV_LINK_STATUS: + metric_in |= NHDP_KD_LM_INC; + metric_in |= (metric_in == metric_out) ? NHDP_KD_LM_OUT : 0x00; + break; + case RFC5444_ADDRTLV_OTHER_NEIGHB: + metric_in |= NHDP_KD_NM_INC; + metric_in |= (metric_in == metric_out) ? NHDP_KD_NM_OUT : 0x00; + break; + default: + /* Other types are not used and therefore no address tlv is added */ + return; + } + rfc5444_writer_add_addrtlv(wr, wr_addr, &_nhdp_addrtlvs[RFC5444_ADDRTLV_LINK_METRIC], + &metric_in, sizeof(metric_in), true); + } } diff --git a/sys/net/routing/nhdp/nhdp_writer.h b/sys/net/routing/nhdp/nhdp_writer.h index 2998e0f82c..111ab0f740 100644 --- a/sys/net/routing/nhdp/nhdp_writer.h +++ b/sys/net/routing/nhdp/nhdp_writer.h @@ -65,9 +65,12 @@ void nhdp_writer_send_hello(nhdp_if_entry_t *if_entry); * @param[in] addr Pointer to a NHDP address to add to the HELLO message * @param[in] type TLV type for the address * @param[in] value TLV value for the address + * @param[in] metric_in Encoded incoming link metric value + * @param[in] metric_out Encoded outgoing link metric value */ void nhdp_writer_add_addr(struct rfc5444_writer *wr, nhdp_addr_t *addr, - enum rfc5444_addrtlv_iana type, uint8_t value); + enum rfc5444_addrtlv_iana type, uint8_t value, + uint16_t metric_in, uint16_t metric_out); #ifdef __cplusplus } diff --git a/sys/net/routing/nhdp/nib_table.c b/sys/net/routing/nhdp/nib_table.c index 4d73ac8a7e..8e922eb552 100644 --- a/sys/net/routing/nhdp/nib_table.c +++ b/sys/net/routing/nhdp/nib_table.c @@ -122,7 +122,9 @@ void nib_fill_wr_addresses(struct rfc5444_writer *wr) /* Check whether address is not already included with link status symmetric */ if (!NHDP_ADDR_TMP_IN_SYM(addr_elt->address)) { nhdp_writer_add_addr(wr, addr_elt->address, RFC5444_ADDRTLV_OTHER_NEIGHB, - RFC5444_OTHERNEIGHB_SYMMETRIC); + RFC5444_OTHERNEIGHB_SYMMETRIC, + rfc5444_metric_encode(nib_elt->metric_in), + rfc5444_metric_encode(nib_elt->metric_out)); addr_elt->address->in_tmp_table = NHDP_ADDR_TMP_SYM; } } @@ -140,7 +142,8 @@ void nib_fill_wr_addresses(struct rfc5444_writer *wr) if (!NHDP_ADDR_TMP_IN_ANY(lost_elt->address)) { /* Address is not present in one of the lists, add it */ nhdp_writer_add_addr(wr, lost_elt->address, RFC5444_ADDRTLV_OTHER_NEIGHB, - RFC5444_OTHERNEIGHB_LOST); + RFC5444_OTHERNEIGHB_LOST, NHDP_METRIC_UNKNOWN, + NHDP_METRIC_UNKNOWN); } } } @@ -215,6 +218,8 @@ static nib_entry_t *add_nib_entry_for_nb_addr_list(void) } new_elem->symmetric = 0; + new_elem->metric_in = NHDP_METRIC_UNKNOWN; + new_elem->metric_out = NHDP_METRIC_UNKNOWN; LL_PREPEND(nib_entry_head, new_elem); return new_elem; diff --git a/sys/net/routing/nhdp/nib_table.h b/sys/net/routing/nhdp/nib_table.h index bb9c93f35b..f995ca3cd6 100644 --- a/sys/net/routing/nhdp/nib_table.h +++ b/sys/net/routing/nhdp/nib_table.h @@ -35,6 +35,8 @@ extern "C" { typedef struct nib_entry_t { nhdp_addr_entry_t *address_list_head; /**< Pointer to this tuple's addresses*/ uint8_t symmetric; /**< Flag whether sym link to this nb exists */ + uint32_t metric_in; /**< Lowest metric value for incoming link */ + uint32_t metric_out; /**< Lowest metric value for outgoing link */ struct nib_entry_t *next; /**< Pointer to next list entry */ } nib_entry_t;