|
@@ -1001,6 +1001,32 @@ static inline int is_tcp_reset(const struct sk_buff *skb, int nh_len)
|
|
|
return th->rst;
|
|
|
}
|
|
|
|
|
|
+static inline bool is_new_conn(const struct sk_buff *skb,
|
|
|
+ struct ip_vs_iphdr *iph)
|
|
|
+{
|
|
|
+ switch (iph->protocol) {
|
|
|
+ case IPPROTO_TCP: {
|
|
|
+ struct tcphdr _tcph, *th;
|
|
|
+
|
|
|
+ th = skb_header_pointer(skb, iph->len, sizeof(_tcph), &_tcph);
|
|
|
+ if (th == NULL)
|
|
|
+ return false;
|
|
|
+ return th->syn;
|
|
|
+ }
|
|
|
+ case IPPROTO_SCTP: {
|
|
|
+ sctp_chunkhdr_t *sch, schunk;
|
|
|
+
|
|
|
+ sch = skb_header_pointer(skb, iph->len + sizeof(sctp_sctphdr_t),
|
|
|
+ sizeof(schunk), &schunk);
|
|
|
+ if (sch == NULL)
|
|
|
+ return false;
|
|
|
+ return sch->type == SCTP_CID_INIT;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/* Handle response packets: rewrite addresses and send away...
|
|
|
*/
|
|
|
static unsigned int
|
|
@@ -1612,6 +1638,15 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
|
|
|
* Check if the packet belongs to an existing connection entry
|
|
|
*/
|
|
|
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);
|
|
|
+ __ip_vs_conn_put(cp);
|
|
|
+ cp = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
if (unlikely(!cp) && !iph.fragoffs) {
|
|
|
/* No (second) fragments need to enter here, as nf_defrag_ipv6
|
|
|
* replayed fragment zero will already have created the cp
|