ip_vs_sed.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * IPVS: Shortest Expected Delay scheduling module
  3. *
  4. * Version: $Id: ip_vs_sed.c,v 1.1 2003/05/10 03:06:08 wensong Exp $
  5. *
  6. * Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version
  11. * 2 of the License, or (at your option) any later version.
  12. *
  13. * Changes:
  14. *
  15. */
  16. /*
  17. * The SED algorithm attempts to minimize each job's expected delay until
  18. * completion. The expected delay that the job will experience is
  19. * (Ci + 1) / Ui if sent to the ith server, in which Ci is the number of
  20. * jobs on the the ith server and Ui is the fixed service rate (weight) of
  21. * the ith server. The SED algorithm adopts a greedy policy that each does
  22. * what is in its own best interest, i.e. to join the queue which would
  23. * minimize its expected delay of completion.
  24. *
  25. * See the following paper for more information:
  26. * A. Weinrib and S. Shenker, Greed is not enough: Adaptive load sharing
  27. * in large heterogeneous systems. In Proceedings IEEE INFOCOM'88,
  28. * pages 986-994, 1988.
  29. *
  30. * Thanks must go to Marko Buuri <marko@buuri.name> for talking SED to me.
  31. *
  32. * The difference between SED and WLC is that SED includes the incoming
  33. * job in the cost function (the increment of 1). SED may outperform
  34. * WLC, while scheduling big jobs under larger heterogeneous systems
  35. * (the server weight varies a lot).
  36. *
  37. */
  38. #include <linux/module.h>
  39. #include <linux/kernel.h>
  40. #include <net/ip_vs.h>
  41. static int
  42. ip_vs_sed_init_svc(struct ip_vs_service *svc)
  43. {
  44. return 0;
  45. }
  46. static int
  47. ip_vs_sed_done_svc(struct ip_vs_service *svc)
  48. {
  49. return 0;
  50. }
  51. static int
  52. ip_vs_sed_update_svc(struct ip_vs_service *svc)
  53. {
  54. return 0;
  55. }
  56. static inline unsigned int
  57. ip_vs_sed_dest_overhead(struct ip_vs_dest *dest)
  58. {
  59. /*
  60. * We only use the active connection number in the cost
  61. * calculation here.
  62. */
  63. return atomic_read(&dest->activeconns) + 1;
  64. }
  65. /*
  66. * Weighted Least Connection scheduling
  67. */
  68. static struct ip_vs_dest *
  69. ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
  70. {
  71. struct ip_vs_dest *dest, *least;
  72. unsigned int loh, doh;
  73. IP_VS_DBG(6, "ip_vs_sed_schedule(): Scheduling...\n");
  74. /*
  75. * We calculate the load of each dest server as follows:
  76. * (server expected overhead) / dest->weight
  77. *
  78. * Remember -- no floats in kernel mode!!!
  79. * The comparison of h1*w2 > h2*w1 is equivalent to that of
  80. * h1/w1 > h2/w2
  81. * if every weight is larger than zero.
  82. *
  83. * The server with weight=0 is quiesced and will not receive any
  84. * new connections.
  85. */
  86. list_for_each_entry(dest, &svc->destinations, n_list) {
  87. if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
  88. atomic_read(&dest->weight) > 0) {
  89. least = dest;
  90. loh = ip_vs_sed_dest_overhead(least);
  91. goto nextstage;
  92. }
  93. }
  94. return NULL;
  95. /*
  96. * Find the destination with the least load.
  97. */
  98. nextstage:
  99. list_for_each_entry_continue(dest, &svc->destinations, n_list) {
  100. if (dest->flags & IP_VS_DEST_F_OVERLOAD)
  101. continue;
  102. doh = ip_vs_sed_dest_overhead(dest);
  103. if (loh * atomic_read(&dest->weight) >
  104. doh * atomic_read(&least->weight)) {
  105. least = dest;
  106. loh = doh;
  107. }
  108. }
  109. IP_VS_DBG(6, "SED: server %u.%u.%u.%u:%u "
  110. "activeconns %d refcnt %d weight %d overhead %d\n",
  111. NIPQUAD(least->addr), ntohs(least->port),
  112. atomic_read(&least->activeconns),
  113. atomic_read(&least->refcnt),
  114. atomic_read(&least->weight), loh);
  115. return least;
  116. }
  117. static struct ip_vs_scheduler ip_vs_sed_scheduler =
  118. {
  119. .name = "sed",
  120. .refcnt = ATOMIC_INIT(0),
  121. .module = THIS_MODULE,
  122. .init_service = ip_vs_sed_init_svc,
  123. .done_service = ip_vs_sed_done_svc,
  124. .update_service = ip_vs_sed_update_svc,
  125. .schedule = ip_vs_sed_schedule,
  126. };
  127. static int __init ip_vs_sed_init(void)
  128. {
  129. INIT_LIST_HEAD(&ip_vs_sed_scheduler.n_list);
  130. return register_ip_vs_scheduler(&ip_vs_sed_scheduler);
  131. }
  132. static void __exit ip_vs_sed_cleanup(void)
  133. {
  134. unregister_ip_vs_scheduler(&ip_vs_sed_scheduler);
  135. }
  136. module_init(ip_vs_sed_init);
  137. module_exit(ip_vs_sed_cleanup);
  138. MODULE_LICENSE("GPL");