Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /* Multipath TCP
3 : : *
4 : : * Copyright (c) 2022, SUSE.
5 : : */
6 : :
7 : : #define pr_fmt(fmt) "MPTCP: " fmt
8 : :
9 : : #include <linux/kernel.h>
10 : : #include <linux/module.h>
11 : : #include <linux/list.h>
12 : : #include <linux/rculist.h>
13 : : #include <linux/spinlock.h>
14 : : #include "protocol.h"
15 : :
16 : : static DEFINE_SPINLOCK(mptcp_sched_list_lock);
17 : : static LIST_HEAD(mptcp_sched_list);
18 : :
19 : 417399 : static int mptcp_sched_default_get_subflow(struct mptcp_sock *msk,
20 : : struct mptcp_sched_data *data)
21 : : {
22 : 417399 : struct sock *ssk;
23 : :
24 [ + + + + ]: 417399 : ssk = data->reinject ? mptcp_subflow_get_retrans(msk) :
25 : 415694 : mptcp_subflow_get_send(msk);
26 [ + + ]: 417399 : if (!ssk)
27 : : return -EINVAL;
28 : :
29 : 340153 : mptcp_subflow_set_scheduled(mptcp_subflow_ctx(ssk), true);
30 : 340153 : return 0;
31 : : }
32 : :
33 : : static struct mptcp_sched_ops mptcp_sched_default = {
34 : : .get_subflow = mptcp_sched_default_get_subflow,
35 : : .name = "default",
36 : : .owner = THIS_MODULE,
37 : : };
38 : :
39 : : /* Must be called with rcu read lock held */
40 : 2618 : struct mptcp_sched_ops *mptcp_sched_find(const char *name)
41 : : {
42 : 2618 : struct mptcp_sched_ops *sched, *ret = NULL;
43 : :
44 [ + + - + : 2768 : list_for_each_entry_rcu(sched, &mptcp_sched_list, list) {
- - - - -
- + + ]
45 [ + + ]: 2704 : if (!strcmp(sched->name, name)) {
46 : : ret = sched;
47 : : break;
48 : : }
49 : : }
50 : :
51 : 2618 : return ret;
52 : : }
53 : :
54 : : /* Build string with list of available scheduler values.
55 : : * Similar to tcp_get_available_congestion_control()
56 : : */
57 : 8 : void mptcp_get_available_schedulers(char *buf, size_t maxlen)
58 : : {
59 : 8 : struct mptcp_sched_ops *sched;
60 : 8 : size_t offs = 0;
61 : :
62 : 8 : rcu_read_lock();
63 [ + + - + : 16 : list_for_each_entry_rcu(sched, &mptcp_sched_list, list) {
- - - - -
- + + ]
64 : 16 : offs += snprintf(buf + offs, maxlen - offs,
65 : : "%s%s",
66 [ - + ]: 8 : offs == 0 ? "" : " ", sched->name);
67 : :
68 [ - + + - ]: 8 : if (WARN_ON_ONCE(offs >= maxlen))
69 : : break;
70 : : }
71 : 8 : rcu_read_unlock();
72 : 8 : }
73 : :
74 : 34 : int mptcp_register_scheduler(struct mptcp_sched_ops *sched)
75 : : {
76 [ + - ]: 34 : if (!sched->get_subflow)
77 : : return -EINVAL;
78 : :
79 : 34 : spin_lock(&mptcp_sched_list_lock);
80 [ - + ]: 34 : if (mptcp_sched_find(sched->name)) {
81 : 0 : spin_unlock(&mptcp_sched_list_lock);
82 : 0 : return -EEXIST;
83 : : }
84 : 34 : list_add_tail_rcu(&sched->list, &mptcp_sched_list);
85 : 33 : spin_unlock(&mptcp_sched_list_lock);
86 : :
87 [ - + ]: 34 : pr_debug("%s registered\n", sched->name);
88 : : return 0;
89 : : }
90 : :
91 : 30 : void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched)
92 : : {
93 [ + - ]: 30 : if (sched == &mptcp_sched_default)
94 : : return;
95 : :
96 : 30 : spin_lock(&mptcp_sched_list_lock);
97 : 30 : list_del_rcu(&sched->list);
98 : 30 : spin_unlock(&mptcp_sched_list_lock);
99 : : }
100 : :
101 : 4 : void mptcp_sched_init(void)
102 : : {
103 : 4 : mptcp_register_scheduler(&mptcp_sched_default);
104 : 4 : }
105 : :
106 : 3680 : int mptcp_init_sched(struct mptcp_sock *msk,
107 : : struct mptcp_sched_ops *sched)
108 : : {
109 [ - + ]: 3680 : if (!sched)
110 : 0 : sched = &mptcp_sched_default;
111 : :
112 [ + - ]: 3680 : if (!bpf_try_module_get(sched, sched->owner))
113 : : return -EBUSY;
114 : :
115 : 3680 : msk->sched = sched;
116 [ + + ]: 3680 : if (msk->sched->init)
117 : 90 : msk->sched->init(msk);
118 : :
119 [ - + ]: 3680 : pr_debug("sched=%s\n", msk->sched->name);
120 : :
121 : : return 0;
122 : : }
123 : :
124 : 3587 : void mptcp_release_sched(struct mptcp_sock *msk)
125 : : {
126 : 3587 : struct mptcp_sched_ops *sched = msk->sched;
127 : :
128 [ + - ]: 3587 : if (!sched)
129 : : return;
130 : :
131 : 3587 : msk->sched = NULL;
132 [ + + ]: 3587 : if (sched->release)
133 : 90 : sched->release(msk);
134 : :
135 : 3587 : bpf_module_put(sched, sched->owner);
136 : : }
137 : :
138 : 320655 : void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow,
139 : : bool scheduled)
140 : : {
141 : 0 : WRITE_ONCE(subflow->scheduled, scheduled);
142 : 839468 : }
143 : :
144 : 196099 : static void mptcp_sched_data_set_contexts(const struct mptcp_sock *msk,
145 : : struct mptcp_sched_data *data)
146 : : {
147 : 196099 : struct mptcp_subflow_context *subflow;
148 : 196099 : int i = 0;
149 : :
150 [ + + ]: 587546 : mptcp_for_each_subflow(msk, subflow) {
151 [ - + ]: 391447 : if (i == MPTCP_SUBFLOWS_MAX) {
152 [ # # # # ]: 0 : pr_warn_once("too many subflows");
153 : : break;
154 : : }
155 : 391447 : mptcp_subflow_set_scheduled(subflow, false);
156 : 391447 : data->contexts[i++] = subflow;
157 : : }
158 : 196099 : data->subflows = i;
159 : :
160 [ + + ]: 1373444 : for (; i < MPTCP_SUBFLOWS_MAX; i++)
161 : 1177345 : data->contexts[i] = NULL;
162 : 196099 : }
163 : :
164 : 661884 : int mptcp_sched_get_send(struct mptcp_sock *msk)
165 : : {
166 : 661884 : struct mptcp_subflow_context *subflow;
167 : 661884 : struct mptcp_sched_data data;
168 : :
169 : 661884 : msk_owned_by_me(msk);
170 : :
171 : : /* the following check is moved out of mptcp_subflow_get_send */
172 [ + + ]: 661884 : if (__mptcp_check_fallback(msk)) {
173 [ + - + - ]: 59224 : if (msk->first &&
174 [ + + ]: 53339 : __tcp_can_send(msk->first) &&
175 [ # # ]: 29612 : sk_stream_memory_free(msk->first)) {
176 : 23406 : mptcp_subflow_set_scheduled(mptcp_subflow_ctx(msk->first), true);
177 : 23406 : return 0;
178 : : }
179 : 6206 : return -EINVAL;
180 : : }
181 : :
182 [ + + ]: 1804015 : mptcp_for_each_subflow(msk, subflow) {
183 [ + + + + ]: 1195148 : if (READ_ONCE(subflow->scheduled))
184 : : return 0;
185 : : }
186 : :
187 : 608867 : data.reinject = false;
188 [ + + - + ]: 608867 : if (msk->sched == &mptcp_sched_default || !msk->sched)
189 : 415694 : return mptcp_sched_default_get_subflow(msk, &data);
190 : 193173 : mptcp_sched_data_set_contexts(msk, &data);
191 : 193173 : return msk->sched->get_subflow(msk, &data);
192 : : }
193 : :
194 : 9682 : int mptcp_sched_get_retrans(struct mptcp_sock *msk)
195 : : {
196 : 9682 : struct mptcp_subflow_context *subflow;
197 : 9682 : struct mptcp_sched_data data;
198 : :
199 : 9682 : msk_owned_by_me(msk);
200 : :
201 : : /* the following check is moved out of mptcp_subflow_get_retrans */
202 [ + + ]: 9682 : if (__mptcp_check_fallback(msk))
203 : : return -EINVAL;
204 : :
205 [ + + ]: 13592 : mptcp_for_each_subflow(msk, subflow) {
206 [ + + + + ]: 8961 : if (READ_ONCE(subflow->scheduled))
207 : : return 0;
208 : : }
209 : :
210 : 4631 : data.reinject = true;
211 [ + + + + ]: 4631 : if (msk->sched == &mptcp_sched_default || !msk->sched)
212 : 1705 : return mptcp_sched_default_get_subflow(msk, &data);
213 : 2926 : mptcp_sched_data_set_contexts(msk, &data);
214 : 2926 : return msk->sched->get_subflow(msk, &data);
215 : : }
|