ip_vs_dh.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * IPVS: Destination Hashing scheduling module
  3. *
  4. * Version: $Id: ip_vs_dh.c,v 1.5 2002/09/15 08:14:08 wensong Exp $
  5. *
  6. * Authors: Wensong Zhang <wensong@gnuchina.org>
  7. *
  8. * Inspired by the consistent hashing scheduler patch from
  9. * Thomas Proell <proellt@gmx.de>
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License
  13. * as published by the Free Software Foundation; either version
  14. * 2 of the License, or (at your option) any later version.
  15. *
  16. * Changes:
  17. *
  18. */
  19. /*
  20. * The dh algorithm is to select server by the hash key of destination IP
  21. * address. The pseudo code is as follows:
  22. *
  23. * n <- servernode[dest_ip];
  24. * if (n is dead) OR
  25. * (n is overloaded) OR (n.weight <= 0) then
  26. * return NULL;
  27. *
  28. * return n;
  29. *
  30. * Notes that servernode is a 256-bucket hash table that maps the hash
  31. * index derived from packet destination IP address to the current server
  32. * array. If the dh scheduler is used in cache cluster, it is good to
  33. * combine it with cache_bypass feature. When the statically assigned
  34. * server is dead or overloaded, the load balancer can bypass the cache
  35. * server and send requests to the original server directly.
  36. *
  37. */
  38. #include <linux/module.h>
  39. #include <linux/kernel.h>
  40. #include <net/ip_vs.h>
  41. /*
  42. * IPVS DH bucket
  43. */
  44. struct ip_vs_dh_bucket {
  45. struct ip_vs_dest *dest; /* real server (cache) */
  46. };
  47. /*
  48. * for IPVS DH entry hash table
  49. */
  50. #ifndef CONFIG_IP_VS_DH_TAB_BITS
  51. #define CONFIG_IP_VS_DH_TAB_BITS 8
  52. #endif
  53. #define IP_VS_DH_TAB_BITS CONFIG_IP_VS_DH_TAB_BITS
  54. #define IP_VS_DH_TAB_SIZE (1 << IP_VS_DH_TAB_BITS)
  55. #define IP_VS_DH_TAB_MASK (IP_VS_DH_TAB_SIZE - 1)
  56. /*
  57. * Returns hash value for IPVS DH entry
  58. */
  59. static inline unsigned ip_vs_dh_hashkey(__u32 addr)
  60. {
  61. return (ntohl(addr)*2654435761UL) & IP_VS_DH_TAB_MASK;
  62. }
  63. /*
  64. * Get ip_vs_dest associated with supplied parameters.
  65. */
  66. static inline struct ip_vs_dest *
  67. ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __u32 addr)
  68. {
  69. return (tbl[ip_vs_dh_hashkey(addr)]).dest;
  70. }
  71. /*
  72. * Assign all the hash buckets of the specified table with the service.
  73. */
  74. static int
  75. ip_vs_dh_assign(struct ip_vs_dh_bucket *tbl, struct ip_vs_service *svc)
  76. {
  77. int i;
  78. struct ip_vs_dh_bucket *b;
  79. struct list_head *p;
  80. struct ip_vs_dest *dest;
  81. b = tbl;
  82. p = &svc->destinations;
  83. for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
  84. if (list_empty(p)) {
  85. b->dest = NULL;
  86. } else {
  87. if (p == &svc->destinations)
  88. p = p->next;
  89. dest = list_entry(p, struct ip_vs_dest, n_list);
  90. atomic_inc(&dest->refcnt);
  91. b->dest = dest;
  92. p = p->next;
  93. }
  94. b++;
  95. }
  96. return 0;
  97. }
  98. /*
  99. * Flush all the hash buckets of the specified table.
  100. */
  101. static void ip_vs_dh_flush(struct ip_vs_dh_bucket *tbl)
  102. {
  103. int i;
  104. struct ip_vs_dh_bucket *b;
  105. b = tbl;
  106. for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
  107. if (b->dest) {
  108. atomic_dec(&b->dest->refcnt);
  109. b->dest = NULL;
  110. }
  111. b++;
  112. }
  113. }
  114. static int ip_vs_dh_init_svc(struct ip_vs_service *svc)
  115. {
  116. struct ip_vs_dh_bucket *tbl;
  117. /* allocate the DH table for this service */
  118. tbl = kmalloc(sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE,
  119. GFP_ATOMIC);
  120. if (tbl == NULL) {
  121. IP_VS_ERR("ip_vs_dh_init_svc(): no memory\n");
  122. return -ENOMEM;
  123. }
  124. svc->sched_data = tbl;
  125. IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) allocated for "
  126. "current service\n",
  127. sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
  128. /* assign the hash buckets with the updated service */
  129. ip_vs_dh_assign(tbl, svc);
  130. return 0;
  131. }
  132. static int ip_vs_dh_done_svc(struct ip_vs_service *svc)
  133. {
  134. struct ip_vs_dh_bucket *tbl = svc->sched_data;
  135. /* got to clean up hash buckets here */
  136. ip_vs_dh_flush(tbl);
  137. /* release the table itself */
  138. kfree(svc->sched_data);
  139. IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) released\n",
  140. sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
  141. return 0;
  142. }
  143. static int ip_vs_dh_update_svc(struct ip_vs_service *svc)
  144. {
  145. struct ip_vs_dh_bucket *tbl = svc->sched_data;
  146. /* got to clean up hash buckets here */
  147. ip_vs_dh_flush(tbl);
  148. /* assign the hash buckets with the updated service */
  149. ip_vs_dh_assign(tbl, svc);
  150. return 0;
  151. }
  152. /*
  153. * If the dest flags is set with IP_VS_DEST_F_OVERLOAD,
  154. * consider that the server is overloaded here.
  155. */
  156. static inline int is_overloaded(struct ip_vs_dest *dest)
  157. {
  158. return dest->flags & IP_VS_DEST_F_OVERLOAD;
  159. }
  160. /*
  161. * Destination hashing scheduling
  162. */
  163. static struct ip_vs_dest *
  164. ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
  165. {
  166. struct ip_vs_dest *dest;
  167. struct ip_vs_dh_bucket *tbl;
  168. struct iphdr *iph = skb->nh.iph;
  169. IP_VS_DBG(6, "ip_vs_dh_schedule(): Scheduling...\n");
  170. tbl = (struct ip_vs_dh_bucket *)svc->sched_data;
  171. dest = ip_vs_dh_get(tbl, iph->daddr);
  172. if (!dest
  173. || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
  174. || atomic_read(&dest->weight) <= 0
  175. || is_overloaded(dest)) {
  176. return NULL;
  177. }
  178. IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u "
  179. "--> server %u.%u.%u.%u:%d\n",
  180. NIPQUAD(iph->daddr),
  181. NIPQUAD(dest->addr),
  182. ntohs(dest->port));
  183. return dest;
  184. }
  185. /*
  186. * IPVS DH Scheduler structure
  187. */
  188. static struct ip_vs_scheduler ip_vs_dh_scheduler =
  189. {
  190. .name = "dh",
  191. .refcnt = ATOMIC_INIT(0),
  192. .module = THIS_MODULE,
  193. .init_service = ip_vs_dh_init_svc,
  194. .done_service = ip_vs_dh_done_svc,
  195. .update_service = ip_vs_dh_update_svc,
  196. .schedule = ip_vs_dh_schedule,
  197. };
  198. static int __init ip_vs_dh_init(void)
  199. {
  200. INIT_LIST_HEAD(&ip_vs_dh_scheduler.n_list);
  201. return register_ip_vs_scheduler(&ip_vs_dh_scheduler);
  202. }
  203. static void __exit ip_vs_dh_cleanup(void)
  204. {
  205. unregister_ip_vs_scheduler(&ip_vs_dh_scheduler);
  206. }
  207. module_init(ip_vs_dh_init);
  208. module_exit(ip_vs_dh_cleanup);
  209. MODULE_LICENSE("GPL");