diff --git a/Documentation/networking/ipvs-sysctl.txt b/Documentation/networking/ipvs-sysctl.txt index 056898685d408e463f1a191f36e2384e9974ab6d..46d2f9bdf9ad47dc689724ec68106cb0488d7666 100644 --- a/Documentation/networking/ipvs-sysctl.txt +++ b/Documentation/networking/ipvs-sysctl.txt @@ -43,6 +43,29 @@ conn_reuse_mode - INTEGER balancer in Direct Routing mode. This bit helps on adding new real servers to a very busy cluster. +conn_reuse_old_conntrack - BOOLEAN + - 0 - disabled (default) + - not 0 - enabled + + If set, when a new TCP syn packet hits an old ipvs connection + table and need reschedule to a new dest: if + 1) the packet uses conntrack + 2) the old ipvs connection table is not a master control + connection (E.g. the command connection of passive FTP) + 3) the old ipvs connection table hasn't been controlled by any + connection (E.g. the data connection of passive FTP) + ipvs will not release the old conntrack, just let the conntrack + reopen the old session as it is a new one. This is an optimization + option selectable by the system administrator. + + If not set, when a new TCP syn packet hits an old ipvs connection + table and need reschedule to a new dest: if + 1) the packet uses conntrack + ipvs just drops this syn packet, expires the old connection by timer. + This will cause the client to retransmit TCP SYN. + + Only has effect when conn_reuse_mode not 0. + conntrack - BOOLEAN 0 - disabled (default) not 0 - enabled diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index af0ede9ad4d0bf5ab74c217af2b5a782db96a3e3..33f210c2a89b1367479ef4acf6d51919dbc19cb7 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -924,6 +924,7 @@ struct netns_ipvs { int sysctl_pmtu_disc; int sysctl_backup_only; int sysctl_conn_reuse_mode; + int sysctl_conn_reuse_old_conntrack; int sysctl_schedule_icmp; int sysctl_ignore_tunneled; @@ -1045,6 +1046,11 @@ static inline int sysctl_conn_reuse_mode(struct netns_ipvs *ipvs) return ipvs->sysctl_conn_reuse_mode; } +static inline int sysctl_conn_reuse_old_conntrack(struct netns_ipvs *ipvs) +{ + return ipvs->sysctl_conn_reuse_old_conntrack; +} + static inline int sysctl_schedule_icmp(struct netns_ipvs *ipvs) { return ipvs->sysctl_schedule_icmp; @@ -1132,6 +1138,11 @@ static inline int sysctl_conn_reuse_mode(struct netns_ipvs *ipvs) return 1; } +static inline int sysctl_conn_reuse_old_conntrack(struct netns_ipvs *ipvs) +{ + return 0; +} + static inline int sysctl_schedule_icmp(struct netns_ipvs *ipvs) { return 0; diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index a71f777d1353abf16509c8389fd3863860ba0562..80cfd71bc3ae5ae6381aac36a3ad43ad173d90ef 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1928,7 +1928,7 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int conn_reuse_mode = sysctl_conn_reuse_mode(ipvs); if (conn_reuse_mode && !iph.fragoffs && is_new_conn(skb, &iph) && cp) { - bool uses_ct = false, resched = false; + bool uses_ct = false, resched = false, drop = false; if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest && unlikely(!atomic_read(&cp->dest->weight))) { @@ -1948,10 +1948,17 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int } if (resched) { + if (uses_ct) { + if (likely(!atomic_read(&cp->n_control) && !cp->control) && + likely(sysctl_conn_reuse_old_conntrack(ipvs))) + cp->flags &= ~IP_VS_CONN_F_NFCT; + else + drop = true; + } if (!atomic_read(&cp->n_control)) ip_vs_conn_expire_now(cp); __ip_vs_conn_put(cp); - if (uses_ct) + if (drop) return NF_DROP; cp = NULL; } diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index c339b5e386b7802c5b8f8293269645c10c8d9d11..4f37dbec3f3a10cb764d227a47ecb1221620ca9b 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1891,6 +1891,12 @@ static struct ctl_table vs_vars[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "conn_reuse_old_conntrack", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { .procname = "schedule_icmp", .maxlen = sizeof(int), @@ -3951,7 +3957,9 @@ static int __net_init ip_vs_control_net_init_sysctl(struct netns_ipvs *ipvs) tbl[idx++].data = &ipvs->sysctl_pmtu_disc; tbl[idx++].data = &ipvs->sysctl_backup_only; ipvs->sysctl_conn_reuse_mode = 1; + ipvs->sysctl_conn_reuse_old_conntrack = 0; tbl[idx++].data = &ipvs->sysctl_conn_reuse_mode; + tbl[idx++].data = &ipvs->sysctl_conn_reuse_old_conntrack; tbl[idx++].data = &ipvs->sysctl_schedule_icmp; tbl[idx++].data = &ipvs->sysctl_ignore_tunneled;