Skip to content

Commit

Permalink
ipvs: avoid expiring many connections from timer
Browse files Browse the repository at this point in the history
Add new functions ip_vs_conn_del() and ip_vs_conn_del_put()
to release many IPVS connections in process context.
They are suitable for connections found in table
when we do not want to overload the timers.

Currently, the change is useful for the dropentry delayed
work but it will be used also in following patch
when flushing connections to failed destinations.

Signed-off-by: Julian Anastasov <ja@ssi.bg>
Reviewed-by: Simon Horman <horms@verge.net.au>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Julian Anastasov authored and intel-lab-lkp committed Jul 8, 2020
1 parent e1c1a2f commit ab29454
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 17 deletions.
53 changes: 38 additions & 15 deletions net/netfilter/ipvs/ip_vs_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,31 @@ static void ip_vs_conn_rcu_free(struct rcu_head *head)
kmem_cache_free(ip_vs_conn_cachep, cp);
}

/* Try to delete connection while not holding reference */
static void ip_vs_conn_del(struct ip_vs_conn *cp)
{
if (del_timer(&cp->timer)) {
/* Drop cp->control chain too */
if (cp->control)
cp->timeout = 0;
ip_vs_conn_expire(&cp->timer);
}
}

/* Try to delete connection while holding reference */
static void ip_vs_conn_del_put(struct ip_vs_conn *cp)
{
if (del_timer(&cp->timer)) {
/* Drop cp->control chain too */
if (cp->control)
cp->timeout = 0;
__ip_vs_conn_put(cp);
ip_vs_conn_expire(&cp->timer);
} else {
__ip_vs_conn_put(cp);
}
}

static void ip_vs_conn_expire(struct timer_list *t)
{
struct ip_vs_conn *cp = from_timer(cp, t, timer);
Expand All @@ -827,14 +852,17 @@ static void ip_vs_conn_expire(struct timer_list *t)

/* does anybody control me? */
if (ct) {
bool has_ref = !cp->timeout && __ip_vs_conn_get(ct);

ip_vs_control_del(cp);
/* Drop CTL or non-assured TPL if not used anymore */
if (!cp->timeout && !atomic_read(&ct->n_control) &&
if (has_ref && !atomic_read(&ct->n_control) &&
(!(ct->flags & IP_VS_CONN_F_TEMPLATE) ||
!(ct->state & IP_VS_CTPL_S_ASSURED))) {
IP_VS_DBG(4, "drop controlling connection\n");
ct->timeout = 0;
ip_vs_conn_expire_now(ct);
ip_vs_conn_del_put(ct);
} else if (has_ref) {
__ip_vs_conn_put(ct);
}
}

Expand Down Expand Up @@ -1317,8 +1345,7 @@ void ip_vs_random_dropentry(struct netns_ipvs *ipvs)

drop:
IP_VS_DBG(4, "drop connection\n");
cp->timeout = 0;
ip_vs_conn_expire_now(cp);
ip_vs_conn_del(cp);
}
cond_resched_rcu();
}
Expand All @@ -1341,19 +1368,15 @@ static void ip_vs_conn_flush(struct netns_ipvs *ipvs)
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
if (cp->ipvs != ipvs)
continue;
/* As timers are expired in LIFO order, restart
* the timer of controlling connection first, so
* that it is expired after us.
*/
if (atomic_read(&cp->n_control))
continue;
cp_c = cp->control;
/* cp->control is valid only with reference to cp */
if (cp_c && __ip_vs_conn_get(cp)) {
IP_VS_DBG(4, "del connection\n");
ip_vs_conn_del(cp);
if (cp_c && !atomic_read(&cp_c->n_control)) {
IP_VS_DBG(4, "del controlling connection\n");
ip_vs_conn_expire_now(cp_c);
__ip_vs_conn_put(cp);
ip_vs_conn_del(cp_c);
}
IP_VS_DBG(4, "del connection\n");
ip_vs_conn_expire_now(cp);
}
cond_resched_rcu();
}
Expand Down
6 changes: 4 additions & 2 deletions net/netfilter/ipvs/ip_vs_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ static void defense_work_handler(struct work_struct *work)
update_defense_level(ipvs);
if (atomic_read(&ipvs->dropentry))
ip_vs_random_dropentry(ipvs);
schedule_delayed_work(&ipvs->defense_work, DEFENSE_TIMER_PERIOD);
queue_delayed_work(system_long_wq, &ipvs->defense_work,
DEFENSE_TIMER_PERIOD);
}
#endif

Expand Down Expand Up @@ -4082,7 +4083,8 @@ static int __net_init ip_vs_control_net_init_sysctl(struct netns_ipvs *ipvs)
ipvs->sysctl_tbl = tbl;
/* Schedule defense work */
INIT_DELAYED_WORK(&ipvs->defense_work, defense_work_handler);
schedule_delayed_work(&ipvs->defense_work, DEFENSE_TIMER_PERIOD);
queue_delayed_work(system_long_wq, &ipvs->defense_work,
DEFENSE_TIMER_PERIOD);

return 0;
}
Expand Down

0 comments on commit ab29454

Please sign in to comment.