|
@@ -1042,6 +1042,26 @@ static inline bool is_new_conn(const struct sk_buff *skb,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static inline bool is_new_conn_expected(const struct ip_vs_conn *cp,
|
|
|
+ int conn_reuse_mode)
|
|
|
+{
|
|
|
+ /* Controlled (FTP DATA or persistence)? */
|
|
|
+ if (cp->control)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ switch (cp->protocol) {
|
|
|
+ case IPPROTO_TCP:
|
|
|
+ return (cp->state == IP_VS_TCP_S_TIME_WAIT) ||
|
|
|
+ ((conn_reuse_mode & 2) &&
|
|
|
+ (cp->state == IP_VS_TCP_S_FIN_WAIT) &&
|
|
|
+ (cp->flags & IP_VS_CONN_F_NOOUTPUT));
|
|
|
+ case IPPROTO_SCTP:
|
|
|
+ return cp->state == IP_VS_SCTP_S_CLOSED;
|
|
|
+ default:
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* Handle response packets: rewrite addresses and send away...
|
|
|
*/
|
|
|
static unsigned int
|
|
@@ -1580,6 +1600,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
|
|
|
struct ip_vs_conn *cp;
|
|
|
int ret, pkts;
|
|
|
struct netns_ipvs *ipvs;
|
|
|
+ int conn_reuse_mode;
|
|
|
|
|
|
/* Already marked as IPVS request or reply? */
|
|
|
if (skb->ipvs_property)
|
|
@@ -1648,10 +1669,14 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
|
|
|
*/
|
|
|
cp = pp->conn_in_get(af, skb, &iph, 0);
|
|
|
|
|
|
- if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp && cp->dest &&
|
|
|
- unlikely(!atomic_read(&cp->dest->weight)) && !iph.fragoffs &&
|
|
|
- is_new_conn(skb, &iph)) {
|
|
|
- ip_vs_conn_expire_now(cp);
|
|
|
+ conn_reuse_mode = sysctl_conn_reuse_mode(ipvs);
|
|
|
+ if (conn_reuse_mode && !iph.fragoffs &&
|
|
|
+ is_new_conn(skb, &iph) && cp &&
|
|
|
+ ((unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
|
|
|
+ unlikely(!atomic_read(&cp->dest->weight))) ||
|
|
|
+ unlikely(is_new_conn_expected(cp, conn_reuse_mode)))) {
|
|
|
+ if (!atomic_read(&cp->n_control))
|
|
|
+ ip_vs_conn_expire_now(cp);
|
|
|
__ip_vs_conn_put(cp);
|
|
|
cp = NULL;
|
|
|
}
|