Skip to content
Permalink
Browse files

net/iface: Coalesce all RS timers through one

This reduces the size of struct net_if_ipv6 by 24 bytes by moving
the k_delayed_work attribute into net_if core code.
Then each net_if_ipv6 can be added to the timer handler via a slist.

This does not make much gain if the system has only 1 network interface
It starts to be interesting if it has 2+ network interfaces then.

Fixes #8728

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
  • Loading branch information...
tbursztyka authored and jukkar committed May 21, 2019
1 parent 09e7262 commit b5bcd25398be166a5b23406d51c0f02aa7bafc38
Showing with 90 additions and 28 deletions.
  1. +24 −5 include/net/net_if.h
  2. +1 −1 subsys/net/ip/ipv6_nbr.c
  3. +65 −22 subsys/net/ip/net_if.c
@@ -220,9 +220,6 @@ struct net_if_ipv6 {
/** Prefixes */
struct net_if_ipv6_prefix prefix[NET_IF_MAX_IPV6_PREFIX];

/** Router solicitation timer */
struct k_delayed_work rs_timer;

/** Default reachable time (RFC 4861, page 52) */
u32_t base_reachable_time;

@@ -231,12 +228,19 @@ struct net_if_ipv6 {

/** Retransmit timer (RFC 4861, page 52) */
u32_t retrans_timer;
#if defined(CONFIG_NET_IPV6_ND)
/** Router solicitation timer node */
sys_snode_t rs_node;

/** IPv6 hop limit */
u8_t hop_limit;
/* RS start time */
u32_t rs_start;

/** RS count */
u8_t rs_count;
#endif

/** IPv6 hop limit */
u8_t hop_limit;
};

/** @cond INTERNAL_HIDDEN */
@@ -659,6 +663,21 @@ static inline void net_if_start_dad(struct net_if *iface)
*/
void net_if_start_rs(struct net_if *iface);


/**
* @brief Stop neighbor discovery.
*
* @param iface Pointer to a network interface structure
*/
#if defined(CONFIG_NET_IPV6_ND)
void net_if_stop_rs(struct net_if *iface);
#else
static inline void net_if_stop_rs(struct net_if *iface)
{
ARG_UNUSED(iface);
}
#endif /* CONFIG_NET_IPV6_ND */

/**
* @brief Set a network interface's link address
*
@@ -2429,7 +2429,7 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt,
}

/* Cancel the RS timer on iface */
k_delayed_work_cancel(&net_pkt_iface(pkt)->config.ip.ipv6->rs_timer);
net_if_stop_rs(net_pkt_iface(pkt));

net_pkt_unref(pkt);

@@ -65,6 +65,11 @@ static struct k_delayed_work dad_timer;
static sys_slist_t active_dad_timers;
#endif

#if defined(CONFIG_NET_IPV6_ND)
static struct k_delayed_work rs_timer;
static sys_slist_t active_rs_timers;
#endif

static struct {
struct net_if_ipv6 ipv6;
struct net_if *iface;
@@ -742,29 +747,48 @@ static inline void net_if_ipv6_start_dad(struct net_if *iface,

static void rs_timeout(struct k_work *work)
{
/* Did not receive RA yet. */
struct net_if_ipv6 *ipv6 = CONTAINER_OF(work,
struct net_if_ipv6,
rs_timer);
struct net_if *iface;
u32_t current_time = k_uptime_get_32();
struct net_if_ipv6 *ipv6, *next;

ipv6->rs_count++;
ARG_UNUSED(work);

for (iface = __net_if_start; iface != __net_if_end; iface++) {
if (iface->config.ip.ipv6 == ipv6) {
goto found;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&active_rs_timers,
ipv6, next, rs_node) {
struct net_if *iface;

if ((s32_t)(ipv6->rs_start + RS_TIMEOUT - current_time) > 0) {
break;
}

/* Removing the ipv6 from active_rs_timers list */
sys_slist_remove(&active_rs_timers, NULL, &ipv6->rs_node);

/* Did not receive RA yet. */
ipv6->rs_count++;

for (iface = __net_if_start; iface != __net_if_end; iface++) {
if (iface->config.ip.ipv6 == ipv6) {
break;
}
}
}

NET_DBG("Interface IPv6 config %p not found", ipv6);
return;
if (iface != __net_if_end) {
NET_DBG("RS no respond iface %p count %d",
iface, ipv6->rs_count);
if (ipv6->rs_count < RS_COUNT) {
net_if_start_rs(iface);
}
} else {
NET_DBG("Interface IPv6 config %p not found", ipv6);
}

found:
NET_DBG("RS no respond iface %p count %d", iface,
ipv6->rs_count);
ipv6 = NULL;
}

if (ipv6->rs_count < RS_COUNT) {
net_if_start_rs(iface);
if (ipv6) {
k_delayed_work_submit(&rs_timer,
ipv6->rs_start +
RS_TIMEOUT - current_time);
}
}

@@ -779,17 +803,37 @@ void net_if_start_rs(struct net_if *iface)
NET_DBG("Starting ND/RS for iface %p", iface);

if (!net_ipv6_start_rs(iface)) {
k_delayed_work_submit(&ipv6->rs_timer, RS_TIMEOUT);
ipv6->rs_start = k_uptime_get_32();
sys_slist_append(&active_rs_timers, &ipv6->rs_node);

if (!k_delayed_work_remaining_get(&rs_timer)) {
k_delayed_work_submit(&rs_timer, RS_TIMEOUT);
}
}
}

static inline void iface_ipv6_nd_init(struct net_if_ipv6 *ipv6)
void net_if_stop_rs(struct net_if *iface)
{
k_delayed_work_init(&ipv6->rs_timer, rs_timeout);
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;

if (!ipv6) {
return;
}

NET_DBG("Stopping ND/RS for iface %p", iface);

sys_slist_find_and_remove(&active_rs_timers, &ipv6->rs_node);
}

static inline void iface_ipv6_nd_init(void)
{
k_delayed_work_init(&rs_timer, rs_timeout);
sys_slist_init(&active_rs_timers);
}

#else
#define net_if_start_rs(...)
#define net_if_stop_rs(...)
#define iface_ipv6_nd_init(...)
#endif /* CONFIG_NET_IPV6_ND */

@@ -2207,6 +2251,7 @@ static void iface_ipv6_init(int if_count)
int i;

iface_ipv6_dad_init();
iface_ipv6_nd_init();

k_delayed_work_init(&address_lifetime_timer, address_lifetime_timeout);
k_delayed_work_init(&prefix_lifetime_timer, prefix_lifetime_timeout);
@@ -2224,8 +2269,6 @@ static void iface_ipv6_init(int if_count)
ipv6_addresses[i].ipv6.base_reachable_time = REACHABLE_TIME;

net_if_ipv6_set_reachable_time(&ipv6_addresses[i].ipv6);

iface_ipv6_nd_init(&ipv6_addresses[i].ipv6);
}
}

0 comments on commit b5bcd25

Please sign in to comment.
You can’t perform that action at this time.