ip_vs_sched.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * IPVS An implementation of the IP virtual server support for the
  3. * LINUX operating system. IPVS is now implemented as a module
  4. * over the Netfilter framework. IPVS can be used to build a
  5. * high-performance and highly available server based on a
  6. * cluster of servers.
  7. *
  8. * Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
  9. * Peter Kese <peter.kese@ijs.si>
  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. #include <linux/module.h>
  20. #include <linux/spinlock.h>
  21. #include <linux/interrupt.h>
  22. #include <asm/string.h>
  23. #include <linux/kmod.h>
  24. #include <linux/sysctl.h>
  25. #include <net/ip_vs.h>
  26. /*
  27. * IPVS scheduler list
  28. */
  29. static LIST_HEAD(ip_vs_schedulers);
  30. /* lock for service table */
  31. static DEFINE_RWLOCK(__ip_vs_sched_lock);
  32. /*
  33. * Bind a service with a scheduler
  34. */
  35. int ip_vs_bind_scheduler(struct ip_vs_service *svc,
  36. struct ip_vs_scheduler *scheduler)
  37. {
  38. int ret;
  39. if (svc == NULL) {
  40. IP_VS_ERR("ip_vs_bind_scheduler(): svc arg NULL\n");
  41. return -EINVAL;
  42. }
  43. if (scheduler == NULL) {
  44. IP_VS_ERR("ip_vs_bind_scheduler(): scheduler arg NULL\n");
  45. return -EINVAL;
  46. }
  47. svc->scheduler = scheduler;
  48. if (scheduler->init_service) {
  49. ret = scheduler->init_service(svc);
  50. if (ret) {
  51. IP_VS_ERR("ip_vs_bind_scheduler(): init error\n");
  52. return ret;
  53. }
  54. }
  55. return 0;
  56. }
  57. /*
  58. * Unbind a service with its scheduler
  59. */
  60. int ip_vs_unbind_scheduler(struct ip_vs_service *svc)
  61. {
  62. struct ip_vs_scheduler *sched;
  63. if (svc == NULL) {
  64. IP_VS_ERR("ip_vs_unbind_scheduler(): svc arg NULL\n");
  65. return -EINVAL;
  66. }
  67. sched = svc->scheduler;
  68. if (sched == NULL) {
  69. IP_VS_ERR("ip_vs_unbind_scheduler(): svc isn't bound\n");
  70. return -EINVAL;
  71. }
  72. if (sched->done_service) {
  73. if (sched->done_service(svc) != 0) {
  74. IP_VS_ERR("ip_vs_unbind_scheduler(): done error\n");
  75. return -EINVAL;
  76. }
  77. }
  78. svc->scheduler = NULL;
  79. return 0;
  80. }
  81. /*
  82. * Get scheduler in the scheduler list by name
  83. */
  84. static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name)
  85. {
  86. struct ip_vs_scheduler *sched;
  87. IP_VS_DBG(2, "ip_vs_sched_getbyname(): sched_name \"%s\"\n",
  88. sched_name);
  89. read_lock_bh(&__ip_vs_sched_lock);
  90. list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
  91. /*
  92. * Test and get the modules atomically
  93. */
  94. if (sched->module && !try_module_get(sched->module)) {
  95. /*
  96. * This scheduler is just deleted
  97. */
  98. continue;
  99. }
  100. if (strcmp(sched_name, sched->name)==0) {
  101. /* HIT */
  102. read_unlock_bh(&__ip_vs_sched_lock);
  103. return sched;
  104. }
  105. if (sched->module)
  106. module_put(sched->module);
  107. }
  108. read_unlock_bh(&__ip_vs_sched_lock);
  109. return NULL;
  110. }
  111. /*
  112. * Lookup scheduler and try to load it if it doesn't exist
  113. */
  114. struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name)
  115. {
  116. struct ip_vs_scheduler *sched;
  117. /*
  118. * Search for the scheduler by sched_name
  119. */
  120. sched = ip_vs_sched_getbyname(sched_name);
  121. /*
  122. * If scheduler not found, load the module and search again
  123. */
  124. if (sched == NULL) {
  125. request_module("ip_vs_%s", sched_name);
  126. sched = ip_vs_sched_getbyname(sched_name);
  127. }
  128. return sched;
  129. }
  130. void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler)
  131. {
  132. if (scheduler->module)
  133. module_put(scheduler->module);
  134. }
  135. /*
  136. * Register a scheduler in the scheduler list
  137. */
  138. int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
  139. {
  140. struct ip_vs_scheduler *sched;
  141. if (!scheduler) {
  142. IP_VS_ERR("register_ip_vs_scheduler(): NULL arg\n");
  143. return -EINVAL;
  144. }
  145. if (!scheduler->name) {
  146. IP_VS_ERR("register_ip_vs_scheduler(): NULL scheduler_name\n");
  147. return -EINVAL;
  148. }
  149. /* increase the module use count */
  150. ip_vs_use_count_inc();
  151. write_lock_bh(&__ip_vs_sched_lock);
  152. if (scheduler->n_list.next != &scheduler->n_list) {
  153. write_unlock_bh(&__ip_vs_sched_lock);
  154. ip_vs_use_count_dec();
  155. IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler "
  156. "already linked\n", scheduler->name);
  157. return -EINVAL;
  158. }
  159. /*
  160. * Make sure that the scheduler with this name doesn't exist
  161. * in the scheduler list.
  162. */
  163. list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
  164. if (strcmp(scheduler->name, sched->name) == 0) {
  165. write_unlock_bh(&__ip_vs_sched_lock);
  166. ip_vs_use_count_dec();
  167. IP_VS_ERR("register_ip_vs_scheduler(): [%s] scheduler "
  168. "already existed in the system\n",
  169. scheduler->name);
  170. return -EINVAL;
  171. }
  172. }
  173. /*
  174. * Add it into the d-linked scheduler list
  175. */
  176. list_add(&scheduler->n_list, &ip_vs_schedulers);
  177. write_unlock_bh(&__ip_vs_sched_lock);
  178. IP_VS_INFO("[%s] scheduler registered.\n", scheduler->name);
  179. return 0;
  180. }
  181. /*
  182. * Unregister a scheduler from the scheduler list
  183. */
  184. int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
  185. {
  186. if (!scheduler) {
  187. IP_VS_ERR( "unregister_ip_vs_scheduler(): NULL arg\n");
  188. return -EINVAL;
  189. }
  190. write_lock_bh(&__ip_vs_sched_lock);
  191. if (scheduler->n_list.next == &scheduler->n_list) {
  192. write_unlock_bh(&__ip_vs_sched_lock);
  193. IP_VS_ERR("unregister_ip_vs_scheduler(): [%s] scheduler "
  194. "is not in the list. failed\n", scheduler->name);
  195. return -EINVAL;
  196. }
  197. /*
  198. * Remove it from the d-linked scheduler list
  199. */
  200. list_del(&scheduler->n_list);
  201. write_unlock_bh(&__ip_vs_sched_lock);
  202. /* decrease the module use count */
  203. ip_vs_use_count_dec();
  204. IP_VS_INFO("[%s] scheduler unregistered.\n", scheduler->name);
  205. return 0;
  206. }