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 : 364895 : static int mptcp_sched_default_get_subflow(struct mptcp_sock *msk,
20 : : struct mptcp_sched_data *data)
21 : : {
22 : 364895 : struct sock *ssk;
23 : :
24 [ + + + + ]: 364895 : ssk = data->reinject ? mptcp_subflow_get_retrans(msk) :
25 : 363320 : mptcp_subflow_get_send(msk);
26 [ + + ]: 364895 : if (!ssk)
27 : : return -EINVAL;
28 : :
29 : 302117 : mptcp_subflow_set_scheduled(mptcp_subflow_ctx(ssk), true);
30 : 302117 : 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 : 2438 : struct mptcp_sched_ops *mptcp_sched_find(const char *name)
41 : : {
42 : 2438 : struct mptcp_sched_ops *sched, *ret = NULL;
43 : :
44 [ + + - + : 2438 : list_for_each_entry_rcu(sched, &mptcp_sched_list, list) {
- - - - -
- + + ]
45 [ - + ]: 2434 : if (!strcmp(sched->name, name)) {
46 : : ret = sched;
47 : : break;
48 : : }
49 : : }
50 : :
51 : 2438 : 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 : 4 : int mptcp_register_scheduler(struct mptcp_sched_ops *sched)
75 : : {
76 [ + - ]: 4 : if (!sched->get_subflow)
77 : : return -EINVAL;
78 : :
79 : 4 : spin_lock(&mptcp_sched_list_lock);
80 [ - + ]: 4 : if (mptcp_sched_find(sched->name)) {
81 : 0 : spin_unlock(&mptcp_sched_list_lock);
82 : 0 : return -EEXIST;
83 : : }
84 : 4 : list_add_tail_rcu(&sched->list, &mptcp_sched_list);
85 : 3 : spin_unlock(&mptcp_sched_list_lock);
86 : :
87 [ - + ]: 4 : pr_debug("%s registered\n", sched->name);
88 : : return 0;
89 : : }
90 : :
91 : 0 : void mptcp_unregister_scheduler(struct mptcp_sched_ops *sched)
92 : : {
93 [ # # ]: 0 : if (sched == &mptcp_sched_default)
94 : : return;
95 : :
96 : 0 : spin_lock(&mptcp_sched_list_lock);
97 : 0 : list_del_rcu(&sched->list);
98 : 0 : 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 : 3554 : int mptcp_init_sched(struct mptcp_sock *msk,
107 : : struct mptcp_sched_ops *sched)
108 : : {
109 [ - + ]: 3554 : if (!sched)
110 : 0 : sched = &mptcp_sched_default;
111 : :
112 [ + - ]: 3554 : if (!bpf_try_module_get(sched, sched->owner))
113 : : return -EBUSY;
114 : :
115 : 3554 : msk->sched = sched;
116 [ - + ]: 3554 : if (msk->sched->init)
117 : 0 : msk->sched->init(msk);
118 : :
119 [ - + ]: 3554 : pr_debug("sched=%s\n", msk->sched->name);
120 : :
121 : : return 0;
122 : : }
123 : :
124 : 3461 : void mptcp_release_sched(struct mptcp_sock *msk)
125 : : {
126 : 3461 : struct mptcp_sched_ops *sched = msk->sched;
127 : :
128 [ + - ]: 3461 : if (!sched)
129 : : return;
130 : :
131 : 3461 : msk->sched = NULL;
132 [ - + ]: 3461 : if (sched->release)
133 : 0 : sched->release(msk);
134 : :
135 : 3461 : bpf_module_put(sched, sched->owner);
136 : : }
137 : :
138 : 334700 : void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow,
139 : : bool scheduled)
140 : : {
141 : 302103 : WRITE_ONCE(subflow->scheduled, scheduled);
142 : 334712 : }
143 : :
144 : 407004 : int mptcp_sched_get_send(struct mptcp_sock *msk)
145 : : {
146 : 407004 : struct mptcp_subflow_context *subflow;
147 : 407004 : struct mptcp_sched_data data;
148 : :
149 : 407004 : msk_owned_by_me(msk);
150 : :
151 : : /* the following check is moved out of mptcp_subflow_get_send */
152 [ + + ]: 407004 : if (__mptcp_check_fallback(msk)) {
153 [ + - + - ]: 84630 : if (msk->first &&
154 [ + + ]: 65171 : __tcp_can_send(msk->first) &&
155 [ # # ]: 42315 : sk_stream_memory_free(msk->first)) {
156 : 32999 : mptcp_subflow_set_scheduled(mptcp_subflow_ctx(msk->first), true);
157 : 32999 : return 0;
158 : : }
159 : 9316 : return -EINVAL;
160 : : }
161 : :
162 [ + + ]: 1039268 : mptcp_for_each_subflow(msk, subflow) {
163 [ + + + + ]: 675948 : if (READ_ONCE(subflow->scheduled))
164 : : return 0;
165 : : }
166 : :
167 : 363320 : data.reinject = false;
168 [ - + - - ]: 363320 : if (msk->sched == &mptcp_sched_default || !msk->sched)
169 : 363320 : return mptcp_sched_default_get_subflow(msk, &data);
170 : 0 : return msk->sched->get_subflow(msk, &data);
171 : : }
172 : :
173 : 7506 : int mptcp_sched_get_retrans(struct mptcp_sock *msk)
174 : : {
175 : 7506 : struct mptcp_subflow_context *subflow;
176 : 7506 : struct mptcp_sched_data data;
177 : :
178 : 7506 : msk_owned_by_me(msk);
179 : :
180 : : /* the following check is moved out of mptcp_subflow_get_retrans */
181 [ + + ]: 7506 : if (__mptcp_check_fallback(msk))
182 : : return -EINVAL;
183 : :
184 [ + + ]: 4427 : mptcp_for_each_subflow(msk, subflow) {
185 [ + + + + ]: 2852 : if (READ_ONCE(subflow->scheduled))
186 : : return 0;
187 : : }
188 : :
189 : 1575 : data.reinject = true;
190 [ + + + - ]: 1575 : if (msk->sched == &mptcp_sched_default || !msk->sched)
191 : 1575 : return mptcp_sched_default_get_subflow(msk, &data);
192 : 0 : return msk->sched->get_subflow(msk, &data);
193 : : }
|