]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv4/ipvs/ip_vs_ctl.c
IPVS: Convert real server lookup functions
[net-next-2.6.git] / net / ipv4 / ipvs / ip_vs_ctl.c
index a2d69b2ce6a1dae6951dd8deca6f53ab2cd53d66..bb0e1e3c8857376f4af84f0038097a373ae2d275 100644 (file)
@@ -421,23 +421,24 @@ __ip_vs_svc_fwm_get(int af, __u32 fwmark)
 }
 
 struct ip_vs_service *
-ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
+ip_vs_service_get(int af, __u32 fwmark, __u16 protocol,
+                 const union nf_inet_addr *vaddr, __be16 vport)
 {
        struct ip_vs_service *svc;
-       union nf_inet_addr _vaddr = { .ip = vaddr };
+
        read_lock(&__ip_vs_svc_lock);
 
        /*
         *      Check the table hashed by fwmark first
         */
-       if (fwmark && (svc = __ip_vs_svc_fwm_get(AF_INET, fwmark)))
+       if (fwmark && (svc = __ip_vs_svc_fwm_get(af, fwmark)))
                goto out;
 
        /*
         *      Check the table hashed by <protocol,addr,port>
         *      for "full" addressed entries
         */
-       svc = __ip_vs_service_get(AF_INET, protocol, &_vaddr, vport);
+       svc = __ip_vs_service_get(af, protocol, vaddr, vport);
 
        if (svc == NULL
            && protocol == IPPROTO_TCP
@@ -447,7 +448,7 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
                 * Check if ftp service entry exists, the packet
                 * might belong to FTP data connections.
                 */
-               svc = __ip_vs_service_get(AF_INET, protocol, &_vaddr, FTPPORT);
+               svc = __ip_vs_service_get(af, protocol, vaddr, FTPPORT);
        }
 
        if (svc == NULL
@@ -455,16 +456,16 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
                /*
                 * Check if the catch-all port (port zero) exists
                 */
-               svc = __ip_vs_service_get(AF_INET, protocol, &_vaddr, 0);
+               svc = __ip_vs_service_get(af, protocol, vaddr, 0);
        }
 
   out:
        read_unlock(&__ip_vs_svc_lock);
 
-       IP_VS_DBG(9, "lookup service: fwm %u %s %u.%u.%u.%u:%u %s\n",
-                 fwmark, ip_vs_proto_name(protocol),
-                 NIPQUAD(vaddr), ntohs(vport),
-                 svc?"hit":"not hit");
+       IP_VS_DBG_BUF(9, "lookup service: fwm %u %s %s:%u %s\n",
+                     fwmark, ip_vs_proto_name(protocol),
+                     IP_VS_DBG_ADDR(af, vaddr), ntohs(vport),
+                     svc ? "hit" : "not hit");
 
        return svc;
 }
@@ -491,11 +492,20 @@ __ip_vs_unbind_svc(struct ip_vs_dest *dest)
 /*
  *     Returns hash value for real service
  */
-static __inline__ unsigned ip_vs_rs_hashkey(__be32 addr, __be16 port)
+static inline unsigned ip_vs_rs_hashkey(int af,
+                                           const union nf_inet_addr *addr,
+                                           __be16 port)
 {
        register unsigned porth = ntohs(port);
+       __be32 addr_fold = addr->ip;
+
+#ifdef CONFIG_IP_VS_IPV6
+       if (af == AF_INET6)
+               addr_fold = addr->ip6[0]^addr->ip6[1]^
+                           addr->ip6[2]^addr->ip6[3];
+#endif
 
-       return (ntohl(addr)^(porth>>IP_VS_RTAB_BITS)^porth)
+       return (ntohl(addr_fold)^(porth>>IP_VS_RTAB_BITS)^porth)
                & IP_VS_RTAB_MASK;
 }
 
@@ -515,7 +525,8 @@ static int ip_vs_rs_hash(struct ip_vs_dest *dest)
         *      Hash by proto,addr,port,
         *      which are the parameters of the real service.
         */
-       hash = ip_vs_rs_hashkey(dest->addr.ip, dest->port);
+       hash = ip_vs_rs_hashkey(dest->af, &dest->addr, dest->port);
+
        list_add(&dest->d_list, &ip_vs_rtable[hash]);
 
        return 1;
@@ -542,7 +553,9 @@ static int ip_vs_rs_unhash(struct ip_vs_dest *dest)
  *     Lookup real service by <proto,addr,port> in the real service table.
  */
 struct ip_vs_dest *
-ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
+ip_vs_lookup_real_service(int af, __u16 protocol,
+                         const union nf_inet_addr *daddr,
+                         __be16 dport)
 {
        unsigned hash;
        struct ip_vs_dest *dest;
@@ -551,11 +564,12 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
         *      Check for "full" addressed entries
         *      Return the first found entry
         */
-       hash = ip_vs_rs_hashkey(daddr, dport);
+       hash = ip_vs_rs_hashkey(af, daddr, dport);
 
        read_lock(&__ip_vs_rs_lock);
        list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) {
-               if ((dest->addr.ip == daddr)
+               if ((dest->af == af)
+                   && ip_vs_addr_equal(af, &dest->addr, daddr)
                    && (dest->port == dport)
                    && ((dest->protocol == protocol) ||
                        dest->vfwmark)) {
@@ -573,7 +587,8 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
  *     Lookup destination by {addr,port} in the given service
  */
 static struct ip_vs_dest *
-ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
+ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
+                 __be16 dport)
 {
        struct ip_vs_dest *dest;
 
@@ -581,7 +596,9 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
         * Find the destination for the given service
         */
        list_for_each_entry(dest, &svc->destinations, n_list) {
-               if ((dest->addr.ip == daddr) && (dest->port == dport)) {
+               if ((dest->af == svc->af)
+                   && ip_vs_addr_equal(svc->af, &dest->addr, daddr)
+                   && (dest->port == dport)) {
                        /* HIT */
                        return dest;
                }
@@ -600,13 +617,15 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
  * ip_vs_lookup_real_service() looked promissing, but
  * seems not working as expected.
  */
-struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
-                                   __be32 vaddr, __be16 vport, __u16 protocol)
+struct ip_vs_dest *ip_vs_find_dest(int af, const union nf_inet_addr *daddr,
+                                  __be16 dport,
+                                  const union nf_inet_addr *vaddr,
+                                  __be16 vport, __u16 protocol)
 {
        struct ip_vs_dest *dest;
        struct ip_vs_service *svc;
 
-       svc = ip_vs_service_get(0, protocol, vaddr, vport);
+       svc = ip_vs_service_get(af, 0, protocol, vaddr, vport);
        if (!svc)
                return NULL;
        dest = ip_vs_lookup_dest(svc, daddr, dport);
@@ -627,7 +646,8 @@ struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport,
  *  scheduling.
  */
 static struct ip_vs_dest *
-ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
+ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
+                    __be16 dport)
 {
        struct ip_vs_dest *dest, *nxt;
 
@@ -635,17 +655,19 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
         * Find the destination in trash
         */
        list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) {
-               IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, "
-                         "dest->refcnt=%d\n",
-                         dest->vfwmark,
-                         NIPQUAD(dest->addr.ip), ntohs(dest->port),
-                         atomic_read(&dest->refcnt));
-               if (dest->addr.ip == daddr &&
+               IP_VS_DBG_BUF(3, "Destination %u/%s:%u still in trash, "
+                             "dest->refcnt=%d\n",
+                             dest->vfwmark,
+                             IP_VS_DBG_ADDR(svc->af, &dest->addr),
+                             ntohs(dest->port),
+                             atomic_read(&dest->refcnt));
+               if (dest->af == svc->af &&
+                   ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
                    dest->port == dport &&
                    dest->vfwmark == svc->fwmark &&
                    dest->protocol == svc->protocol &&
                    (svc->fwmark ||
-                    (dest->vaddr.ip == svc->addr.ip &&
+                    (ip_vs_addr_equal(svc->af, &dest->vaddr, &svc->addr) &&
                      dest->vport == svc->port))) {
                        /* HIT */
                        return dest;
@@ -655,10 +677,11 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
                 * Try to purge the destination from trash if not referenced
                 */
                if (atomic_read(&dest->refcnt) == 1) {
-                       IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u "
-                                 "from trash\n",
-                                 dest->vfwmark,
-                                 NIPQUAD(dest->addr.ip), ntohs(dest->port));
+                       IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u "
+                                     "from trash\n",
+                                     dest->vfwmark,
+                                     IP_VS_DBG_ADDR(svc->af, &dest->addr),
+                                     ntohs(dest->port));
                        list_del(&dest->n_list);
                        ip_vs_dst_reset(dest);
                        __ip_vs_unbind_svc(dest);
@@ -845,7 +868,8 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
        /*
         * Check if the dest already exists in the list
         */
-       dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
+       dest = ip_vs_lookup_dest(svc, &daddr, dport);
+
        if (dest != NULL) {
                IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n");
                return -EEXIST;
@@ -855,7 +879,8 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
         * Check if the dest already exists in the trash and
         * is from the same service
         */
-       dest = ip_vs_trash_get_dest(svc, daddr.ip, dport);
+       dest = ip_vs_trash_get_dest(svc, &daddr, dport);
+
        if (dest != NULL) {
                IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, "
                          "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n",
@@ -954,7 +979,8 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
        /*
         *  Lookup the destination list
         */
-       dest = ip_vs_lookup_dest(svc, daddr.ip, dport);
+       dest = ip_vs_lookup_dest(svc, &daddr, dport);
+
        if (dest == NULL) {
                IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n");
                return -ENOENT;
@@ -1052,7 +1078,7 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
 
        EnterFunction(2);
 
-       dest = ip_vs_lookup_dest(svc, udest->addr.ip, dport);
+       dest = ip_vs_lookup_dest(svc, &udest->addr, dport);
 
        if (dest == NULL) {
                IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n");