/*
  *     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;
 }
 
         *      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;
  *     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;
         *      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)) {
  *     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;
 
         * 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;
                }
  * 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;
-       union nf_inet_addr _vaddr = { .ip = vaddr };
 
-       svc = ip_vs_service_get(AF_INET, 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);
  *  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;
 
         * 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;
                 * 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);
        /*
         * 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;
         * 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",
        /*
         *  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;
 
        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");