aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2013-03-09 16:25:04 -0500
committerSimon Horman <horms@verge.net.au>2013-03-19 08:21:51 -0400
commit0c12582fbcdea0cbb0dfd224e1c5f9a8428ffa18 (patch)
tree04cdcc7982a7bed6f51bb2b8b55ffcf83c1f9e50 /net
parentcf2e39429c245245db889fffdfbdf3f889a6cb22 (diff)
ipvs: add backup_only flag to avoid loops
Dmitry Akindinov is reporting for a problem where SYNs are looping between the master and backup server when the backup server is used as real server in DR mode and has IPVS rules to function as director. Even when the backup function is enabled we continue to forward traffic and schedule new connections when the current master is using the backup server as real server. While this is not a problem for NAT, for DR and TUN method the backup server can not determine if a request comes from client or from director. To avoid such loops add new sysctl flag backup_only. It can be needed for DR/TUN setups that do not need backup and director function at the same time. When the backup function is enabled we stop any forwarding and pass the traffic to the local stack (real server mode). The flag disables the director function when the backup function is enabled. For setups that enable backup function for some virtual services and director function for other virtual services there should be another more complex solution to support DR/TUN mode, may be to assign per-virtual service syncid value, so that we can differentiate the requests. Reported-by: Dmitry Akindinov <dimak@stalker.com> Tested-by: German Myzovsky <lawyer@sipnet.ru> Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c12
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c7
2 files changed, 15 insertions, 4 deletions
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 47edf5a40a59..18b4bc55fa3d 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -1577,7 +1577,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
1577 } 1577 }
1578 /* ipvs enabled in this netns ? */ 1578 /* ipvs enabled in this netns ? */
1579 net = skb_net(skb); 1579 net = skb_net(skb);
1580 if (!net_ipvs(net)->enable) 1580 ipvs = net_ipvs(net);
1581 if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
1581 return NF_ACCEPT; 1582 return NF_ACCEPT;
1582 1583
1583 ip_vs_fill_iph_skb(af, skb, &iph); 1584 ip_vs_fill_iph_skb(af, skb, &iph);
@@ -1654,7 +1655,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
1654 } 1655 }
1655 1656
1656 IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet"); 1657 IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet");
1657 ipvs = net_ipvs(net);
1658 /* Check the server status */ 1658 /* Check the server status */
1659 if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) { 1659 if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
1660 /* the destination server is not available */ 1660 /* the destination server is not available */
@@ -1815,13 +1815,15 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
1815{ 1815{
1816 int r; 1816 int r;
1817 struct net *net; 1817 struct net *net;
1818 struct netns_ipvs *ipvs;
1818 1819
1819 if (ip_hdr(skb)->protocol != IPPROTO_ICMP) 1820 if (ip_hdr(skb)->protocol != IPPROTO_ICMP)
1820 return NF_ACCEPT; 1821 return NF_ACCEPT;
1821 1822
1822 /* ipvs enabled in this netns ? */ 1823 /* ipvs enabled in this netns ? */
1823 net = skb_net(skb); 1824 net = skb_net(skb);
1824 if (!net_ipvs(net)->enable) 1825 ipvs = net_ipvs(net);
1826 if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
1825 return NF_ACCEPT; 1827 return NF_ACCEPT;
1826 1828
1827 return ip_vs_in_icmp(skb, &r, hooknum); 1829 return ip_vs_in_icmp(skb, &r, hooknum);
@@ -1835,6 +1837,7 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
1835{ 1837{
1836 int r; 1838 int r;
1837 struct net *net; 1839 struct net *net;
1840 struct netns_ipvs *ipvs;
1838 struct ip_vs_iphdr iphdr; 1841 struct ip_vs_iphdr iphdr;
1839 1842
1840 ip_vs_fill_iph_skb(AF_INET6, skb, &iphdr); 1843 ip_vs_fill_iph_skb(AF_INET6, skb, &iphdr);
@@ -1843,7 +1846,8 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
1843 1846
1844 /* ipvs enabled in this netns ? */ 1847 /* ipvs enabled in this netns ? */
1845 net = skb_net(skb); 1848 net = skb_net(skb);
1846 if (!net_ipvs(net)->enable) 1849 ipvs = net_ipvs(net);
1850 if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
1847 return NF_ACCEPT; 1851 return NF_ACCEPT;
1848 1852
1849 return ip_vs_in_icmp_v6(skb, &r, hooknum, &iphdr); 1853 return ip_vs_in_icmp_v6(skb, &r, hooknum, &iphdr);
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index c68198bf9128..9e2d1cccd1eb 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -1808,6 +1808,12 @@ static struct ctl_table vs_vars[] = {
1808 .mode = 0644, 1808 .mode = 0644,
1809 .proc_handler = proc_dointvec, 1809 .proc_handler = proc_dointvec,
1810 }, 1810 },
1811 {
1812 .procname = "backup_only",
1813 .maxlen = sizeof(int),
1814 .mode = 0644,
1815 .proc_handler = proc_dointvec,
1816 },
1811#ifdef CONFIG_IP_VS_DEBUG 1817#ifdef CONFIG_IP_VS_DEBUG
1812 { 1818 {
1813 .procname = "debug_level", 1819 .procname = "debug_level",
@@ -3741,6 +3747,7 @@ static int __net_init ip_vs_control_net_init_sysctl(struct net *net)
3741 tbl[idx++].data = &ipvs->sysctl_nat_icmp_send; 3747 tbl[idx++].data = &ipvs->sysctl_nat_icmp_send;
3742 ipvs->sysctl_pmtu_disc = 1; 3748 ipvs->sysctl_pmtu_disc = 1;
3743 tbl[idx++].data = &ipvs->sysctl_pmtu_disc; 3749 tbl[idx++].data = &ipvs->sysctl_pmtu_disc;
3750 tbl[idx++].data = &ipvs->sysctl_backup_only;
3744 3751
3745 3752
3746 ipvs->sysctl_hdr = register_net_sysctl(net, "net/ipv4/vs", tbl); 3753 ipvs->sysctl_hdr = register_net_sysctl(net, "net/ipv4/vs", tbl);