Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f719e37

Browse files
Julian Anastasovhorms
authored andcommitted
ipvs: drop first packet to redirect conntrack
Jiri Bohac is reporting for a problem where the attempt to reschedule existing connection to another real server needs proper redirect for the conntrack used by the IPVS connection. For example, when IPVS connection is created to NAT-ed real server we alter the reply direction of conntrack. If we later decide to select different real server we can not alter again the conntrack. And if we expire the old connection, the new connection is left without conntrack. So, the only way to redirect both the IPVS connection and the Netfilter's conntrack is to drop the SYN packet that hits existing connection, to wait for the next jiffie to expire the old connection and its conntrack and to rely on client's retransmission to create new connection as usually. Jiri Bohac provided a fix that drops all SYNs on rescheduling, I extended his patch to do such drops only for connections that use conntrack. Here is the original report from Jiri Bohac: Since commit dc7b3eb ("ipvs: Fix reuse connection if real server is dead"), new connections to dead servers are redistributed immediately to new servers. The old connection is expired using ip_vs_conn_expire_now() which sets the connection timer to expire immediately. However, before the timer callback, ip_vs_conn_expire(), is run to clean the connection's conntrack entry, the new redistributed connection may already be established and its conntrack removed instead. Fix this by dropping the first packet of the new connection instead, like we do when the destination server is not available. The timer will have deleted the old conntrack entry long before the first packet of the new connection is retransmitted. Fixes: dc7b3eb ("ipvs: Fix reuse connection if real server is dead") Signed-off-by: Jiri Bohac <[email protected]> Signed-off-by: Julian Anastasov <[email protected]> Signed-off-by: Simon Horman <[email protected]>
1 parent 3f20efb commit f719e37

File tree

2 files changed

+45
-9
lines changed

2 files changed

+45
-9
lines changed

include/net/ip_vs.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,23 @@ static inline void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp)
15881588
}
15891589
#endif /* CONFIG_IP_VS_NFCT */
15901590

1591+
/* Really using conntrack? */
1592+
static inline bool ip_vs_conn_uses_conntrack(struct ip_vs_conn *cp,
1593+
struct sk_buff *skb)
1594+
{
1595+
#ifdef CONFIG_IP_VS_NFCT
1596+
enum ip_conntrack_info ctinfo;
1597+
struct nf_conn *ct;
1598+
1599+
if (!(cp->flags & IP_VS_CONN_F_NFCT))
1600+
return false;
1601+
ct = nf_ct_get(skb, &ctinfo);
1602+
if (ct && !nf_ct_is_untracked(ct))
1603+
return true;
1604+
#endif
1605+
return false;
1606+
}
1607+
15911608
static inline int
15921609
ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
15931610
{

net/netfilter/ipvs/ip_vs_core.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,15 +1757,34 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int
17571757
cp = pp->conn_in_get(ipvs, af, skb, &iph);
17581758

17591759
conn_reuse_mode = sysctl_conn_reuse_mode(ipvs);
1760-
if (conn_reuse_mode && !iph.fragoffs &&
1761-
is_new_conn(skb, &iph) && cp &&
1762-
((unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
1763-
unlikely(!atomic_read(&cp->dest->weight))) ||
1764-
unlikely(is_new_conn_expected(cp, conn_reuse_mode)))) {
1765-
if (!atomic_read(&cp->n_control))
1766-
ip_vs_conn_expire_now(cp);
1767-
__ip_vs_conn_put(cp);
1768-
cp = NULL;
1760+
if (conn_reuse_mode && !iph.fragoffs && is_new_conn(skb, &iph) && cp) {
1761+
bool uses_ct = false, resched = false;
1762+
1763+
if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
1764+
unlikely(!atomic_read(&cp->dest->weight))) {
1765+
resched = true;
1766+
uses_ct = ip_vs_conn_uses_conntrack(cp, skb);
1767+
} else if (is_new_conn_expected(cp, conn_reuse_mode)) {
1768+
uses_ct = ip_vs_conn_uses_conntrack(cp, skb);
1769+
if (!atomic_read(&cp->n_control)) {
1770+
resched = true;
1771+
} else {
1772+
/* Do not reschedule controlling connection
1773+
* that uses conntrack while it is still
1774+
* referenced by controlled connection(s).
1775+
*/
1776+
resched = !uses_ct;
1777+
}
1778+
}
1779+
1780+
if (resched) {
1781+
if (!atomic_read(&cp->n_control))
1782+
ip_vs_conn_expire_now(cp);
1783+
__ip_vs_conn_put(cp);
1784+
if (uses_ct)
1785+
return NF_DROP;
1786+
cp = NULL;
1787+
}
17691788
}
17701789

17711790
if (unlikely(!cp)) {

0 commit comments

Comments
 (0)