LVS
lvs-devel
Google
 
Web LinuxVirtualServer.org

[PATCH 18/26] IPVS: Add functions for getting/creating IPv6 connections.

To: lvs-devel@xxxxxxxxxxxxxxx, netdev@xxxxxxxxxxxxxxx
Subject: [PATCH 18/26] IPVS: Add functions for getting/creating IPv6 connections.
Cc: horms@xxxxxxxxxxxx, davem@xxxxxxxxxxxxx, vbusam@xxxxxxxxxx, "Julius R. Volz" <juliusv@xxxxxxxxxx>
From: "Julius R. Volz" <juliusv@xxxxxxxxxx>
Date: Wed, 11 Jun 2008 19:12:01 +0200
Add functions for getting/creating IPv6 connections and connection
templates where these diverge significantly from the IPv4 versions.

Signed-off-by: Julius R. Volz <juliusv@xxxxxxxxxx>

 2 files changed, 211 insertions(+), 0 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index d04d5c6..6a58dff 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -816,6 +816,19 @@ extern struct ip_vs_conn *ip_vs_ct_in_get
 extern struct ip_vs_conn *ip_vs_conn_out_get
 (int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
 
+#ifdef CONFIG_IP_VS_IPV6
+extern struct ip_vs_conn *
+ip_vs_conn_in_get_v6(int protocol, const struct in6_addr *s_addr, __be16 
s_port,
+                    const struct in6_addr *d_addr, __be16 d_port);
+extern struct ip_vs_conn *
+ip_vs_ct_in_get_v6(int protocol, const struct in6_addr *s_addr, __be16 s_port,
+                  const struct in6_addr *d_addr, __be16 d_port);
+extern struct ip_vs_conn *
+ip_vs_conn_out_get_v6(int protocol, const struct in6_addr *s_addr,
+                     __be16 s_port, const struct in6_addr *d_addr,
+                     __be16 d_port);
+#endif
+
 /* put back the conn without restarting its timer */
 static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
 {
@@ -828,6 +841,15 @@ extern struct ip_vs_conn *
 ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 
vport,
               __be32 daddr, __be16 dport, unsigned flags,
               struct ip_vs_dest *dest);
+
+#ifdef CONFIG_IP_VS_IPV6
+extern struct ip_vs_conn *
+ip_vs_conn_new_v6(int proto, const struct in6_addr *caddr, __be16 cport,
+                 const struct in6_addr *vaddr, __be16 vport,
+                 const struct in6_addr *daddr, __be16 dport, unsigned flags,
+                 struct ip_vs_dest *dest);
+#endif
+
 extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
 
 extern const char * ip_vs_state_name(__u16 proto, int state);
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index 4ee5dac..30e1ad2 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -236,6 +236,36 @@ static inline struct ip_vs_conn *__ip_vs_conn_in_get
        return NULL;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+static inline struct ip_vs_conn *__ip_vs_conn_in_get_v6
+(int protocol, const struct in6_addr *s_addr, __be16 s_port, const struct 
in6_addr *d_addr, __be16 d_port)
+{
+       unsigned hash;
+       struct ip_vs_conn *cp;
+
+       hash = ip_vs_conn_hashkey_v6(protocol, s_addr, s_port);
+
+       ct_read_lock(hash);
+
+       list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+               if (cp->af == AF_INET6 &&
+                   ipv6_addr_equal(s_addr, &cp->caddr.v6) && s_port==cp->cport 
&&
+                   ipv6_addr_equal(d_addr, &cp->vaddr.v6) && d_port==cp->vport 
&&
+                   ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
+                   protocol==cp->protocol) {
+                       /* HIT */
+                       atomic_inc(&cp->refcnt);
+                       ct_read_unlock(hash);
+                       return cp;
+               }
+       }
+
+       ct_read_unlock(hash);
+
+       return NULL;
+}
+#endif
+
 struct ip_vs_conn *ip_vs_conn_in_get
 (int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
 {
@@ -254,6 +284,26 @@ struct ip_vs_conn *ip_vs_conn_in_get
        return cp;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+struct ip_vs_conn *ip_vs_conn_in_get_v6
+(int protocol, const struct in6_addr *s_addr, __be16 s_port, const struct 
in6_addr *d_addr, __be16 d_port)
+{
+       struct ip_vs_conn *cp;
+
+       cp = __ip_vs_conn_in_get_v6(protocol, s_addr, s_port, d_addr, d_port);
+       if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
+               cp = __ip_vs_conn_in_get_v6(protocol, s_addr, 0, d_addr, 
d_port);
+
+       IP_VS_DBG(9, "lookup/in %s " NIP6_FMT ":%d->" NIP6_FMT ":%d %s\n",
+                 ip_vs_proto_name(protocol),
+                 NIP6(*s_addr), ntohs(s_port),
+                 NIP6(*d_addr), ntohs(d_port),
+                 cp?"hit":"not hit");
+
+       return cp;
+}
+#endif
+
 /* Get reference to connection template */
 struct ip_vs_conn *ip_vs_ct_in_get
 (int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
@@ -290,6 +340,44 @@ struct ip_vs_conn *ip_vs_ct_in_get
        return cp;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+/* Get reference to connection template */
+struct ip_vs_conn *ip_vs_ct_in_get_v6
+(int protocol, const struct in6_addr *s_addr, __be16 s_port, const struct 
in6_addr *d_addr, __be16 d_port)
+{
+       unsigned hash;
+       struct ip_vs_conn *cp;
+
+       hash = ip_vs_conn_hashkey_v6(protocol, s_addr, s_port);
+
+       ct_read_lock(hash);
+
+       list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+               if (cp->af == AF_INET6 &&
+                   ipv6_addr_equal(s_addr, &cp->caddr.v6) && s_port==cp->cport 
&&
+                   ipv6_addr_equal(d_addr, &cp->vaddr.v6) && d_port==cp->vport 
&&
+                   cp->flags & IP_VS_CONN_F_TEMPLATE &&
+                   protocol==cp->protocol) {
+                       /* HIT */
+                       atomic_inc(&cp->refcnt);
+                       goto out;
+               }
+       }
+       cp = NULL;
+
+  out:
+       ct_read_unlock(hash);
+
+       IP_VS_DBG(9, "template lookup/in %s " NIP6_FMT ":%d->" NIP6_FMT ":%d 
%s\n",
+                 ip_vs_proto_name(protocol),
+                 NIP6(*s_addr), ntohs(s_port),
+                 NIP6(*d_addr), ntohs(d_port),
+                 cp?"hit":"not hit");
+
+       return cp;
+}
+#endif
+
 /*
  *  Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
  *  Called for pkts coming from inside-to-OUTside.
@@ -332,6 +420,44 @@ struct ip_vs_conn *ip_vs_conn_out_get
        return ret;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+struct ip_vs_conn *ip_vs_conn_out_get_v6
+(int protocol, const struct in6_addr *s_addr, __be16 s_port, const struct 
in6_addr *d_addr, __be16 d_port)
+{
+       unsigned hash;
+       struct ip_vs_conn *cp, *ret=NULL;
+
+       /*
+        *      Check for "full" addressed entries
+        */
+       hash = ip_vs_conn_hashkey_v6(protocol, d_addr, d_port);
+
+       ct_read_lock(hash);
+
+       list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+               if (cp->af == AF_INET6 &&
+                   ipv6_addr_equal(d_addr, &cp->caddr.v6) && d_port==cp->cport 
&&
+                   ipv6_addr_equal(s_addr, &cp->daddr.v6) && s_port==cp->dport 
&&
+                   protocol == cp->protocol) {
+                       /* HIT */
+                       atomic_inc(&cp->refcnt);
+                       ret = cp;
+                       break;
+               }
+       }
+
+       ct_read_unlock(hash);
+
+       IP_VS_DBG(9, "lookup/out %s " NIP6_FMT ":%d->" NIP6_FMT ":%d %s\n",
+                 ip_vs_proto_name(protocol),
+                 NIP6(*s_addr), ntohs(s_port),
+                 NIP6(*d_addr), ntohs(d_port),
+                 ret?"hit":"not hit");
+
+       return ret;
+}
+#endif
+
 
 /*
  *      Put back the conn and restart its timer with its timeout
@@ -766,6 +892,69 @@ ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, 
__be32 vaddr, __be16 vport
        return cp;
 }
 
+#ifdef CONFIG_IP_VS_IPV6
+struct ip_vs_conn *
+ip_vs_conn_new_v6(int proto, const struct in6_addr *caddr, __be16 cport,
+                 const struct in6_addr *vaddr, __be16 vport,
+                 const struct in6_addr *daddr, __be16 dport, unsigned flags,
+                 struct ip_vs_dest *dest)
+{
+       struct ip_vs_conn *cp;
+       struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
+
+       cp = kmem_cache_zalloc(ip_vs_conn_cachep, GFP_ATOMIC);
+       if (cp == NULL) {
+               IP_VS_ERR_RL("ip_vs_conn_new_v6: no memory available.\n");
+               return NULL;
+       }
+
+       INIT_LIST_HEAD(&cp->c_list);
+       setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
+       cp->af             = AF_INET6;
+       cp->protocol       = proto;
+       cp->caddr.v6       = *caddr;
+       cp->cport          = cport;
+       cp->vaddr.v6       = *vaddr;
+       cp->vport          = vport;
+       cp->daddr.v6       = *daddr;
+       cp->dport          = dport;
+       cp->flags          = flags;
+       spin_lock_init(&cp->lock);
+
+       /*
+        * Set the entry is referenced by the current thread before hashing
+        * it in the table, so that other thread run ip_vs_random_dropentry
+        * but cannot drop this entry.
+        */
+       atomic_set(&cp->refcnt, 1);
+
+       atomic_set(&cp->n_control, 0);
+       atomic_set(&cp->in_pkts, 0);
+
+       atomic_inc(&ip_vs_conn_count);
+       if (flags & IP_VS_CONN_F_NO_CPORT)
+               atomic_inc(&ip_vs_conn_no_cport_cnt);
+
+       /* Bind the connection with a destination server */
+       ip_vs_bind_dest(cp, dest);
+
+       /* Set its state and timeout */
+       cp->state = 0;
+       cp->timeout = 3*HZ;
+
+       /* Bind its packet transmitter */
+       ip_vs_bind_xmit_v6(cp);
+
+       if (unlikely(pp && atomic_read(&pp->appcnt)))
+               ip_vs_bind_app(cp, pp);
+
+       /* Hash it in the ip_vs_conn_tab finally */
+       ip_vs_conn_hash(cp);
+
+       return cp;
+}
+#endif
+
 
 /*
  *     /proc/net/ip_vs_conn entries
-- 
1.5.3.6

--
To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

<Prev in Thread] Current Thread [Next in Thread>