Remove network specific default and max log level setting and start to use the zephyr logging values for those. Remove LOG_MODULE_REGISTER() from net_core.h and place the calls into .c files. This is done in order to avoid weird compiler errors in some cases and to make the code look similar as other subsystems. Fixes #11343 Fixes #11659 Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
228 lines
4.5 KiB
C
228 lines
4.5 KiB
C
/** @file
|
|
* @brief Trickle timer library
|
|
*
|
|
* This implements Trickle timer as specified in RFC 6206
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <logging/log.h>
|
|
LOG_MODULE_REGISTER(net_trickle, CONFIG_NET_TRICKLE_LOG_LEVEL);
|
|
|
|
#include <errno.h>
|
|
#include <misc/util.h>
|
|
|
|
#include <net/net_core.h>
|
|
#include <net/trickle.h>
|
|
|
|
#define TICK_MAX ~0
|
|
|
|
static inline bool is_suppression_disabled(struct net_trickle *trickle)
|
|
{
|
|
return trickle->k == NET_TRICKLE_INFINITE_REDUNDANCY;
|
|
}
|
|
|
|
static inline bool is_tx_allowed(struct net_trickle *trickle)
|
|
{
|
|
return is_suppression_disabled(trickle) ||
|
|
(trickle->c < trickle->k);
|
|
}
|
|
|
|
static inline u32_t get_end(struct net_trickle *trickle)
|
|
{
|
|
return trickle->Istart + trickle->I;
|
|
}
|
|
|
|
/* Returns a random time point t in [I/2 , I) */
|
|
static u32_t get_t(u32_t I)
|
|
{
|
|
I >>= 1;
|
|
|
|
NET_DBG("[%d, %d)", I, I << 1);
|
|
|
|
return I + (sys_rand32_get() % I);
|
|
}
|
|
|
|
static void double_interval_timeout(struct k_work *work)
|
|
{
|
|
struct net_trickle *trickle = CONTAINER_OF(work,
|
|
struct net_trickle,
|
|
timer);
|
|
u32_t rand_time;
|
|
u32_t last_end = get_end(trickle);
|
|
|
|
trickle->c = 0;
|
|
|
|
NET_DBG("now %u (was at %u)", k_uptime_get_32(), last_end);
|
|
|
|
/* Check if we need to double the interval */
|
|
if (trickle->I <= (trickle->Imax_abs >> 1)) {
|
|
/* Double if I <= Imax/2 */
|
|
trickle->I <<= 1;
|
|
|
|
NET_DBG("double I %u", trickle->I);
|
|
} else {
|
|
trickle->I = trickle->Imax_abs;
|
|
|
|
NET_DBG("I %u", trickle->I);
|
|
}
|
|
|
|
/* Random t in [I/2, I) */
|
|
rand_time = get_t(trickle->I);
|
|
|
|
NET_DBG("doubling time %u", rand_time);
|
|
|
|
trickle->Istart = k_uptime_get_32() + rand_time;
|
|
|
|
k_delayed_work_submit(&trickle->timer, rand_time);
|
|
|
|
NET_DBG("last end %u new end %u for %u I %u",
|
|
last_end, get_end(trickle), trickle->Istart, trickle->I);
|
|
}
|
|
|
|
static inline void reschedule(struct net_trickle *trickle)
|
|
{
|
|
u32_t now = k_uptime_get_32();
|
|
u32_t diff = get_end(trickle) - now;
|
|
|
|
NET_DBG("now %d end in %d", now, diff);
|
|
|
|
/* Did the clock wrap */
|
|
if ((s32_t)diff < 0) {
|
|
diff = 0U;
|
|
NET_DBG("Clock wrap");
|
|
}
|
|
|
|
k_delayed_work_init(&trickle->timer, double_interval_timeout);
|
|
k_delayed_work_submit(&trickle->timer, diff);
|
|
}
|
|
|
|
static void trickle_timeout(struct k_work *work)
|
|
{
|
|
struct net_trickle *trickle = CONTAINER_OF(work,
|
|
struct net_trickle,
|
|
timer);
|
|
|
|
NET_DBG("Trickle timeout at %d", k_uptime_get_32());
|
|
|
|
if (trickle->cb) {
|
|
NET_DBG("TX ok %d c(%u) < k(%u)",
|
|
is_tx_allowed(trickle), trickle->c, trickle->k);
|
|
|
|
trickle->cb(trickle, is_tx_allowed(trickle),
|
|
trickle->user_data);
|
|
}
|
|
|
|
if (net_trickle_is_running(trickle)) {
|
|
reschedule(trickle);
|
|
}
|
|
}
|
|
|
|
static void setup_new_interval(struct net_trickle *trickle)
|
|
{
|
|
u32_t t;
|
|
|
|
trickle->c = 0;
|
|
|
|
t = get_t(trickle->I);
|
|
|
|
trickle->Istart = k_uptime_get_32();
|
|
|
|
k_delayed_work_submit(&trickle->timer, t);
|
|
|
|
NET_DBG("new interval at %d ends %d t %d I %d",
|
|
trickle->Istart,
|
|
get_end(trickle),
|
|
t,
|
|
trickle->I);
|
|
}
|
|
|
|
#define CHECK_IMIN(Imin) \
|
|
((Imin < 2) || (Imin > (TICK_MAX >> 1)))
|
|
|
|
int net_trickle_create(struct net_trickle *trickle,
|
|
u32_t Imin,
|
|
u8_t Imax,
|
|
u8_t k)
|
|
{
|
|
NET_ASSERT(trickle && Imax > 0 && k > 0 && !CHECK_IMIN(Imin));
|
|
|
|
(void)memset(trickle, 0, sizeof(struct net_trickle));
|
|
|
|
trickle->Imin = Imin;
|
|
trickle->Imax = Imax;
|
|
trickle->Imax_abs = Imin << Imax;
|
|
trickle->k = k;
|
|
|
|
NET_ASSERT(trickle->Imax_abs);
|
|
|
|
NET_DBG("Imin %d Imax %u k %u Imax_abs %d",
|
|
trickle->Imin, trickle->Imax, trickle->k,
|
|
trickle->Imax_abs);
|
|
|
|
k_delayed_work_init(&trickle->timer, trickle_timeout);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int net_trickle_start(struct net_trickle *trickle,
|
|
net_trickle_cb_t cb,
|
|
void *user_data)
|
|
{
|
|
NET_ASSERT(trickle && cb);
|
|
|
|
trickle->cb = cb;
|
|
trickle->user_data = user_data;
|
|
|
|
/* Random I in [Imin , Imax] */
|
|
trickle->I = trickle->Imin +
|
|
(sys_rand32_get() % (trickle->Imax_abs - trickle->Imin + 1));
|
|
|
|
setup_new_interval(trickle);
|
|
|
|
NET_DBG("start %d end %d in [%d , %d)",
|
|
trickle->Istart, get_end(trickle),
|
|
trickle->I >> 1, trickle->I);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int net_trickle_stop(struct net_trickle *trickle)
|
|
{
|
|
NET_ASSERT(trickle);
|
|
|
|
k_delayed_work_cancel(&trickle->timer);
|
|
|
|
trickle->I = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void net_trickle_consistency(struct net_trickle *trickle)
|
|
{
|
|
NET_ASSERT(trickle);
|
|
|
|
if (trickle->c < 0xFF) {
|
|
trickle->c++;
|
|
}
|
|
|
|
NET_DBG("consistency %u", trickle->c);
|
|
}
|
|
|
|
void net_trickle_inconsistency(struct net_trickle *trickle)
|
|
{
|
|
NET_ASSERT(trickle);
|
|
|
|
if (trickle->I != trickle->Imin) {
|
|
NET_DBG("inconsistency");
|
|
|
|
trickle->I = trickle->Imin;
|
|
}
|
|
|
|
setup_new_interval(trickle);
|
|
}
|