]> Pileus Git - ~andy/linux/blobdiff - net/netfilter/ipvs/ip_vs_core.c
ipvs: reorganize dest trash
[~andy/linux] / net / netfilter / ipvs / ip_vs_core.c
index 47edf5a40a5939d2401dc11baa89142b9bcd64b6..939ad11ed534358466a99a4dfc67f3ff06f14dbf 100644 (file)
@@ -69,10 +69,7 @@ EXPORT_SYMBOL(ip_vs_conn_put);
 EXPORT_SYMBOL(ip_vs_get_debug_level);
 #endif
 
-int ip_vs_net_id __read_mostly;
-#ifdef IP_VS_GENERIC_NETNS
-EXPORT_SYMBOL(ip_vs_net_id);
-#endif
+static int ip_vs_net_id __read_mostly;
 /* netns cnt used for uniqueness */
 static atomic_t ipvs_netns_cnt = ATOMIC_INIT(0);
 
@@ -304,8 +301,10 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
                 * template is not available.
                 * return *ignored=0 i.e. ICMP and NF_DROP
                 */
+               rcu_read_lock();
                dest = svc->scheduler->schedule(svc, skb);
                if (!dest) {
+                       rcu_read_unlock();
                        IP_VS_DBG(1, "p-schedule: no dest found.\n");
                        kfree(param.pe_data);
                        *ignored = 0;
@@ -321,6 +320,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
                 * when the template expires */
                ct = ip_vs_conn_new(&param, &dest->addr, dport,
                                    IP_VS_CONN_F_TEMPLATE, dest, skb->mark);
+               rcu_read_unlock();
                if (ct == NULL) {
                        kfree(param.pe_data);
                        *ignored = -1;
@@ -449,8 +449,10 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
                return NULL;
        }
 
+       rcu_read_lock();
        dest = svc->scheduler->schedule(svc, skb);
        if (dest == NULL) {
+               rcu_read_unlock();
                IP_VS_DBG(1, "Schedule: no dest found.\n");
                return NULL;
        }
@@ -471,6 +473,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
                cp = ip_vs_conn_new(&p, &dest->addr,
                                    dest->port ? dest->port : pptr[1],
                                    flags, dest, skb->mark);
+               rcu_read_unlock();
                if (!cp) {
                        *ignored = -1;
                        return NULL;
@@ -1164,9 +1167,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
                                         sizeof(_ports), _ports, &iph);
                if (pptr == NULL)
                        return NF_ACCEPT;       /* Not for me */
-               if (ip_vs_lookup_real_service(net, af, iph.protocol,
-                                             &iph.saddr,
-                                             pptr[0])) {
+               if (ip_vs_has_real_service(net, af, iph.protocol, &iph.saddr,
+                                          pptr[0])) {
                        /*
                         * Notify the real server: there is no
                         * existing entry if it is not RST
@@ -1181,9 +1183,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
                                                iph.len)))) {
 #ifdef CONFIG_IP_VS_IPV6
                                if (af == AF_INET6) {
-                                       struct net *net =
-                                               dev_net(skb_dst(skb)->dev);
-
                                        if (!skb->dev)
                                                skb->dev = net->loopback_dev;
                                        icmpv6_send(skb,
@@ -1394,19 +1393,20 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
                        skb_reset_network_header(skb);
                        IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u\n",
                                &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, mtu);
-                       rcu_read_lock();
                        ipv4_update_pmtu(skb, dev_net(skb->dev),
                                         mtu, 0, 0, 0, 0);
-                       rcu_read_unlock();
                        /* Client uses PMTUD? */
                        if (!(cih->frag_off & htons(IP_DF)))
                                goto ignore_ipip;
                        /* Prefer the resulting PMTU */
                        if (dest) {
-                               spin_lock(&dest->dst_lock);
-                               if (dest->dst_cache)
-                                       mtu = dst_mtu(dest->dst_cache);
-                               spin_unlock(&dest->dst_lock);
+                               struct ip_vs_dest_dst *dest_dst;
+
+                               rcu_read_lock();
+                               dest_dst = rcu_dereference(dest->dest_dst);
+                               if (dest_dst)
+                                       mtu = dst_mtu(dest_dst->dst_cache);
+                               rcu_read_unlock();
                        }
                        if (mtu > 68 + sizeof(struct iphdr))
                                mtu -= sizeof(struct iphdr);
@@ -1577,7 +1577,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
        }
        /* ipvs enabled in this netns ? */
        net = skb_net(skb);
-       if (!net_ipvs(net)->enable)
+       ipvs = net_ipvs(net);
+       if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
                return NF_ACCEPT;
 
        ip_vs_fill_iph_skb(af, skb, &iph);
@@ -1654,7 +1655,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
        }
 
        IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet");
-       ipvs = net_ipvs(net);
        /* Check the server status */
        if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
                /* the destination server is not available */
@@ -1815,13 +1815,15 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
 {
        int r;
        struct net *net;
+       struct netns_ipvs *ipvs;
 
        if (ip_hdr(skb)->protocol != IPPROTO_ICMP)
                return NF_ACCEPT;
 
        /* ipvs enabled in this netns ? */
        net = skb_net(skb);
-       if (!net_ipvs(net)->enable)
+       ipvs = net_ipvs(net);
+       if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
                return NF_ACCEPT;
 
        return ip_vs_in_icmp(skb, &r, hooknum);
@@ -1835,6 +1837,7 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
 {
        int r;
        struct net *net;
+       struct netns_ipvs *ipvs;
        struct ip_vs_iphdr iphdr;
 
        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,
 
        /* ipvs enabled in this netns ? */
        net = skb_net(skb);
-       if (!net_ipvs(net)->enable)
+       ipvs = net_ipvs(net);
+       if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
                return NF_ACCEPT;
 
        return ip_vs_in_icmp_v6(skb, &r, hooknum, &iphdr);