aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_cong.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_cong.c')
-rw-r--r--net/ipv4/tcp_cong.c91
1 files changed, 90 insertions, 1 deletions
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 1e2982f4acd4..5ca7723d0798 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -113,7 +113,7 @@ int tcp_set_default_congestion_control(const char *name)
113 spin_lock(&tcp_cong_list_lock); 113 spin_lock(&tcp_cong_list_lock);
114 ca = tcp_ca_find(name); 114 ca = tcp_ca_find(name);
115#ifdef CONFIG_KMOD 115#ifdef CONFIG_KMOD
116 if (!ca) { 116 if (!ca && capable(CAP_SYS_MODULE)) {
117 spin_unlock(&tcp_cong_list_lock); 117 spin_unlock(&tcp_cong_list_lock);
118 118
119 request_module("tcp_%s", name); 119 request_module("tcp_%s", name);
@@ -123,6 +123,7 @@ int tcp_set_default_congestion_control(const char *name)
123#endif 123#endif
124 124
125 if (ca) { 125 if (ca) {
126 ca->non_restricted = 1; /* default is always allowed */
126 list_move(&ca->list, &tcp_cong_list); 127 list_move(&ca->list, &tcp_cong_list);
127 ret = 0; 128 ret = 0;
128 } 129 }
@@ -139,6 +140,22 @@ static int __init tcp_congestion_default(void)
139late_initcall(tcp_congestion_default); 140late_initcall(tcp_congestion_default);
140 141
141 142
143/* Build string with list of available congestion control values */
144void tcp_get_available_congestion_control(char *buf, size_t maxlen)
145{
146 struct tcp_congestion_ops *ca;
147 size_t offs = 0;
148
149 rcu_read_lock();
150 list_for_each_entry_rcu(ca, &tcp_cong_list, list) {
151 offs += snprintf(buf + offs, maxlen - offs,
152 "%s%s",
153 offs == 0 ? "" : " ", ca->name);
154
155 }
156 rcu_read_unlock();
157}
158
142/* Get current default congestion control */ 159/* Get current default congestion control */
143void tcp_get_default_congestion_control(char *name) 160void tcp_get_default_congestion_control(char *name)
144{ 161{
@@ -152,6 +169,64 @@ void tcp_get_default_congestion_control(char *name)
152 rcu_read_unlock(); 169 rcu_read_unlock();
153} 170}
154 171
172/* Built list of non-restricted congestion control values */
173void tcp_get_allowed_congestion_control(char *buf, size_t maxlen)
174{
175 struct tcp_congestion_ops *ca;
176 size_t offs = 0;
177
178 *buf = '\0';
179 rcu_read_lock();
180 list_for_each_entry_rcu(ca, &tcp_cong_list, list) {
181 if (!ca->non_restricted)
182 continue;
183 offs += snprintf(buf + offs, maxlen - offs,
184 "%s%s",
185 offs == 0 ? "" : " ", ca->name);
186
187 }
188 rcu_read_unlock();
189}
190
191/* Change list of non-restricted congestion control */
192int tcp_set_allowed_congestion_control(char *val)
193{
194 struct tcp_congestion_ops *ca;
195 char *clone, *name;
196 int ret = 0;
197
198 clone = kstrdup(val, GFP_USER);
199 if (!clone)
200 return -ENOMEM;
201
202 spin_lock(&tcp_cong_list_lock);
203 /* pass 1 check for bad entries */
204 while ((name = strsep(&clone, " ")) && *name) {
205 ca = tcp_ca_find(name);
206 if (!ca) {
207 ret = -ENOENT;
208 goto out;
209 }
210 }
211
212 /* pass 2 clear */
213 list_for_each_entry_rcu(ca, &tcp_cong_list, list)
214 ca->non_restricted = 0;
215
216 /* pass 3 mark as allowed */
217 while ((name = strsep(&val, " ")) && *name) {
218 ca = tcp_ca_find(name);
219 WARN_ON(!ca);
220 if (ca)
221 ca->non_restricted = 1;
222 }
223out:
224 spin_unlock(&tcp_cong_list_lock);
225
226 return ret;
227}
228
229
155/* Change congestion control for socket */ 230/* Change congestion control for socket */
156int tcp_set_congestion_control(struct sock *sk, const char *name) 231int tcp_set_congestion_control(struct sock *sk, const char *name)
157{ 232{
@@ -161,12 +236,25 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
161 236
162 rcu_read_lock(); 237 rcu_read_lock();
163 ca = tcp_ca_find(name); 238 ca = tcp_ca_find(name);
239 /* no change asking for existing value */
164 if (ca == icsk->icsk_ca_ops) 240 if (ca == icsk->icsk_ca_ops)
165 goto out; 241 goto out;
166 242
243#ifdef CONFIG_KMOD
244 /* not found attempt to autoload module */
245 if (!ca && capable(CAP_SYS_MODULE)) {
246 rcu_read_unlock();
247 request_module("tcp_%s", name);
248 rcu_read_lock();
249 ca = tcp_ca_find(name);
250 }
251#endif
167 if (!ca) 252 if (!ca)
168 err = -ENOENT; 253 err = -ENOENT;
169 254
255 else if (!(ca->non_restricted || capable(CAP_NET_ADMIN)))
256 err = -EPERM;
257
170 else if (!try_module_get(ca->owner)) 258 else if (!try_module_get(ca->owner))
171 err = -EBUSY; 259 err = -EBUSY;
172 260
@@ -268,6 +356,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd);
268 356
269struct tcp_congestion_ops tcp_reno = { 357struct tcp_congestion_ops tcp_reno = {
270 .name = "reno", 358 .name = "reno",
359 .non_restricted = 1,
271 .owner = THIS_MODULE, 360 .owner = THIS_MODULE,
272 .ssthresh = tcp_reno_ssthresh, 361 .ssthresh = tcp_reno_ssthresh,
273 .cong_avoid = tcp_reno_cong_avoid, 362 .cong_avoid = tcp_reno_cong_avoid,