sched.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Multipath TCP
  3. *
  4. * Copyright (c) 2022, SUSE.
  5. */
  6. #define pr_fmt(fmt) "MPTCP: " fmt
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/list.h>
  10. #include <linux/rculist.h>
  11. #include <linux/spinlock.h>
  12. #include "protocol.h"
  13. static DEFINE_SPINLOCK(mptcp_sched_list_lock);
  14. static LIST_HEAD(mptcp_sched_list);
  15. static int mptcp_sched_default_get_subflow(struct mptcp_sock *msk,
  16. struct mptcp_sched_data *data)
  17. {
  18. struct sock *ssk;
  19. ssk = data->reinject ? mptcp_subflow_get_retrans(msk) :
  20. mptcp_subflow_get_send(msk);
  21. if (!ssk)
  22. return -EINVAL;
  23. mptcp_subflow_set_scheduled(mptcp_subflow_ctx(ssk), true);
  24. return 0;
  25. }
  26. static struct mptcp_sched_ops mptcp_sched_default = {
  27. .get_subflow = mptcp_sched_default_get_subflow,
  28. .name = "default",
  29. .owner = THIS_MODULE,
  30. };
  31. /* Must be called with rcu read lock held */
  32. struct mptcp_sched_ops *mptcp_sched_find(const char *name)
  33. {
  34. struct mptcp_sched_ops *sched, *ret = NULL;
  35. list_for_each_entry_rcu(sched, &mptcp_sched_list, list) {
  36. if (!strcmp(sched->name, name)) {
  37. ret = sched;
  38. break;
  39. }
  40. }
  41. return ret;
  42. }
  43. /* Build string with list of available scheduler values.
  44. * Similar to tcp_get_available_congestion_control()
  45. */
  46. void mptcp_get_available_schedulers(char *buf, size_t maxlen)
  47. {
  48. struct mptcp_sched_ops *sched;
  49. size_t offs = 0;
  50. rcu_read_lock();
  51. spin_lock(&mptcp_sched_list_lock);
  52. list_for_each_entry_rcu(sched, &mptcp_sched_list, list) {
  53. offs += snprintf(buf + offs, maxlen - offs,
  54. "%s%s",
  55. offs == 0 ? "" : " ", sched->name);
  56. if (WARN_ON_ONCE(offs >= maxlen))
  57. break;
  58. }
  59. spin_unlock(&mptcp_sched_list_lock);
  60. rcu_read_unlock();
  61. }
  62. int mptcp_register_scheduler(struct mptcp_sched_ops *sched)
  63. {
  64. if (!sched->get_subflow)
  65. return -EINVAL;
  66. spin_lock(&mptcp_sched_list_lock);
  67. if (mptcp_sched_find(sched->name)) {
  68. spin_unlock(&mptcp_sched_list_lock);
  69. return -EEXIST;
  70. }
  71. list_add_tail_rcu(&sched->list, &mptcp_sched_list);
  72. spin_unlock(&mptcp_sched_list_lock);
  73. pr_debug("%s registered\n", sched->name);
  74. return 0;
  75. }
  76. void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched)
  77. {
  78. if (sched == &mptcp_sched_default)
  79. return;
  80. spin_lock(&mptcp_sched_list_lock);
  81. list_del_rcu(&sched->list);
  82. spin_unlock(&mptcp_sched_list_lock);
  83. }
  84. void mptcp_sched_init(void)
  85. {
  86. mptcp_register_scheduler(&mptcp_sched_default);
  87. }
  88. int mptcp_init_sched(struct mptcp_sock *msk,
  89. struct mptcp_sched_ops *sched)
  90. {
  91. if (!sched)
  92. sched = &mptcp_sched_default;
  93. if (!bpf_try_module_get(sched, sched->owner))
  94. return -EBUSY;
  95. msk->sched = sched;
  96. if (msk->sched->init)
  97. msk->sched->init(msk);
  98. pr_debug("sched=%s\n", msk->sched->name);
  99. return 0;
  100. }
  101. void mptcp_release_sched(struct mptcp_sock *msk)
  102. {
  103. struct mptcp_sched_ops *sched = msk->sched;
  104. if (!sched)
  105. return;
  106. msk->sched = NULL;
  107. if (sched->release)
  108. sched->release(msk);
  109. bpf_module_put(sched, sched->owner);
  110. }
  111. void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow,
  112. bool scheduled)
  113. {
  114. WRITE_ONCE(subflow->scheduled, scheduled);
  115. }
  116. int mptcp_sched_get_send(struct mptcp_sock *msk)
  117. {
  118. struct mptcp_subflow_context *subflow;
  119. struct mptcp_sched_data data;
  120. msk_owned_by_me(msk);
  121. /* the following check is moved out of mptcp_subflow_get_send */
  122. if (__mptcp_check_fallback(msk)) {
  123. if (msk->first &&
  124. __tcp_can_send(msk->first) &&
  125. sk_stream_memory_free(msk->first)) {
  126. mptcp_subflow_set_scheduled(mptcp_subflow_ctx(msk->first), true);
  127. return 0;
  128. }
  129. return -EINVAL;
  130. }
  131. mptcp_for_each_subflow(msk, subflow) {
  132. if (READ_ONCE(subflow->scheduled))
  133. return 0;
  134. }
  135. data.reinject = false;
  136. if (msk->sched == &mptcp_sched_default || !msk->sched)
  137. return mptcp_sched_default_get_subflow(msk, &data);
  138. return msk->sched->get_subflow(msk, &data);
  139. }
  140. int mptcp_sched_get_retrans(struct mptcp_sock *msk)
  141. {
  142. struct mptcp_subflow_context *subflow;
  143. struct mptcp_sched_data data;
  144. msk_owned_by_me(msk);
  145. /* the following check is moved out of mptcp_subflow_get_retrans */
  146. if (__mptcp_check_fallback(msk))
  147. return -EINVAL;
  148. mptcp_for_each_subflow(msk, subflow) {
  149. if (READ_ONCE(subflow->scheduled))
  150. return 0;
  151. }
  152. data.reinject = true;
  153. if (msk->sched == &mptcp_sched_default || !msk->sched)
  154. return mptcp_sched_default_get_subflow(msk, &data);
  155. return msk->sched->get_subflow(msk, &data);
  156. }