|
@@ -825,12 +825,23 @@ static void ip_vs_conn_expire(struct timer_list *t)
|
|
|
|
|
|
/* Unlink conn if not referenced anymore */
|
|
|
if (likely(ip_vs_conn_unlink(cp))) {
|
|
|
+ struct ip_vs_conn *ct = cp->control;
|
|
|
+
|
|
|
/* delete the timer if it is activated by other users */
|
|
|
del_timer(&cp->timer);
|
|
|
|
|
|
/* does anybody control me? */
|
|
|
- if (cp->control)
|
|
|
+ if (ct) {
|
|
|
ip_vs_control_del(cp);
|
|
|
+ /* Drop CTL or non-assured TPL if not used anymore */
|
|
|
+ if (!cp->timeout && !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);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
if ((cp->flags & IP_VS_CONN_F_NFCT) &&
|
|
|
!(cp->flags & IP_VS_CONN_F_ONE_PACKET)) {
|
|
@@ -872,6 +883,10 @@ static void ip_vs_conn_expire(struct timer_list *t)
|
|
|
|
|
|
/* Modify timer, so that it expires as soon as possible.
|
|
|
* Can be called without reference only if under RCU lock.
|
|
|
+ * We can have such chain of conns linked with ->control: DATA->CTL->TPL
|
|
|
+ * - DATA (eg. FTP) and TPL (persistence) can be present depending on setup
|
|
|
+ * - cp->timeout=0 indicates all conns from chain should be dropped but
|
|
|
+ * TPL is not dropped if in assured state
|
|
|
*/
|
|
|
void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
|
|
|
{
|
|
@@ -1197,8 +1212,11 @@ static const struct seq_operations ip_vs_conn_sync_seq_ops = {
|
|
|
#endif
|
|
|
|
|
|
|
|
|
-/*
|
|
|
- * Randomly drop connection entries before running out of memory
|
|
|
+/* Randomly drop connection entries before running out of memory
|
|
|
+ * Can be used for DATA and CTL conns. For TPL conns there are exceptions:
|
|
|
+ * - traffic for services in OPS mode increases ct->in_pkts, so it is supported
|
|
|
+ * - traffic for services not in OPS mode does not increase ct->in_pkts in
|
|
|
+ * all cases, so it is not supported
|
|
|
*/
|
|
|
static inline int todrop_entry(struct ip_vs_conn *cp)
|
|
|
{
|
|
@@ -1242,7 +1260,7 @@ static inline bool ip_vs_conn_ops_mode(struct ip_vs_conn *cp)
|
|
|
void ip_vs_random_dropentry(struct netns_ipvs *ipvs)
|
|
|
{
|
|
|
int idx;
|
|
|
- struct ip_vs_conn *cp, *cp_c;
|
|
|
+ struct ip_vs_conn *cp;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
/*
|
|
@@ -1254,13 +1272,15 @@ void ip_vs_random_dropentry(struct netns_ipvs *ipvs)
|
|
|
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) {
|
|
|
if (cp->ipvs != ipvs)
|
|
|
continue;
|
|
|
+ if (atomic_read(&cp->n_control))
|
|
|
+ continue;
|
|
|
if (cp->flags & IP_VS_CONN_F_TEMPLATE) {
|
|
|
- if (atomic_read(&cp->n_control) ||
|
|
|
- !ip_vs_conn_ops_mode(cp))
|
|
|
- continue;
|
|
|
- else
|
|
|
- /* connection template of OPS */
|
|
|
+ /* connection template of OPS */
|
|
|
+ if (ip_vs_conn_ops_mode(cp))
|
|
|
goto try_drop;
|
|
|
+ if (!(cp->state & IP_VS_CTPL_S_ASSURED))
|
|
|
+ goto drop;
|
|
|
+ continue;
|
|
|
}
|
|
|
if (cp->protocol == IPPROTO_TCP) {
|
|
|
switch(cp->state) {
|
|
@@ -1294,15 +1314,10 @@ try_drop:
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- IP_VS_DBG(4, "del connection\n");
|
|
|
+drop:
|
|
|
+ IP_VS_DBG(4, "drop connection\n");
|
|
|
+ cp->timeout = 0;
|
|
|
ip_vs_conn_expire_now(cp);
|
|
|
- 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 conn template\n");
|
|
|
- ip_vs_conn_expire_now(cp_c);
|
|
|
- __ip_vs_conn_put(cp);
|
|
|
- }
|
|
|
}
|
|
|
cond_resched_rcu();
|
|
|
}
|
|
@@ -1325,15 +1340,19 @@ flush_again:
|
|
|
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
|
|
|
if (cp->ipvs != ipvs)
|
|
|
continue;
|
|
|
- IP_VS_DBG(4, "del connection\n");
|
|
|
- ip_vs_conn_expire_now(cp);
|
|
|
+ /* As timers are expired in LIFO order, restart
|
|
|
+ * the timer of controlling connection first, so
|
|
|
+ * that it is expired after us.
|
|
|
+ */
|
|
|
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 conn template\n");
|
|
|
+ IP_VS_DBG(4, "del controlling connection\n");
|
|
|
ip_vs_conn_expire_now(cp_c);
|
|
|
__ip_vs_conn_put(cp);
|
|
|
}
|
|
|
+ IP_VS_DBG(4, "del connection\n");
|
|
|
+ ip_vs_conn_expire_now(cp);
|
|
|
}
|
|
|
cond_resched_rcu();
|
|
|
}
|