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>
This commit is contained in:
Tomasz Bursztyka 2019-05-21 12:07:08 +02:00 committed by Jukka Rissanen
commit b5bcd25398
3 changed files with 91 additions and 29 deletions

View file

@ -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
*

View file

@ -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);

View file

@ -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,30 +747,49 @@ 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);
u32_t current_time = k_uptime_get_32();
struct net_if_ipv6 *ipv6, *next;
ARG_UNUSED(work);
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) {
goto found;
break;
}
}
NET_DBG("Interface IPv6 config %p not found", ipv6);
return;
found:
NET_DBG("RS no respond iface %p count %d", iface,
ipv6->rs_count);
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);
}
ipv6 = NULL;
}
if (ipv6) {
k_delayed_work_submit(&rs_timer,
ipv6->rs_start +
RS_TIMEOUT - current_time);
}
}
void net_if_start_rs(struct net_if *iface)
@ -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);
}
}